2019浙江省赛 - J
作者:互联网
2019浙江省赛 - J
Welcome Party
题目大意:
n个人,每个人有若干个朋友,他们一个一个进房间。如果i人进入时房间里没有他的朋友,则i人会不开心。请安排顺序使得不开心人数最少。要注意的是,如果1和2是朋友2和3是朋友,那么2和3不是朋友。也就是说朋友关系不会传递。
思路和代码:
首先不开心人数的最小值就是连通块数量。
我一开始以为朋友关系会传递,自信地将顺序排列成123456... (直接wa)
但是朋友关系不会传递,我就想到了拓扑排序。但是这题又不是个拓扑排序 哈哈
用一个优先队列宽搜即可保证点的字典序最小。
还有就是如何让不同连通块之间可以通过bfs搜索到。这里的话就可以用一个超级源点让其和所有连通块的祖先节点连通。(或者说直接把所有祖先节点预先放入搜索队列中)。
ll find(ll u , vct<ll> &fa){
return fa[u] = fa[u] == u ? u : find(fa[u] , fa) ;
}
void solve(){
cin >> n >> m ;
vct<vct<ll> > eg(n + 1) ;
vct<ll> fa(n + 1 , 0) ;
rep(i , 1 , n) fa[i] = i ;
ll ans = n ;
vct<ll> d(n + 1 , 0) ;
rep(i , 1 , m){
ll u , v ;
cin >> u >> v ;
eg[u].pb(v) ;
eg[v].pb(u) ;
d[u] ++ ;
d[v] ++ ;
ll fu = find(u , fa) ;
ll fv = find(v , fa) ;
if(fu == fv) continue ;
ans -- ;
if(fu < fv)fa[fv] = fu ;
else fa[fu] = fa[fv] ;
}
vct<ll> Ans ;
vct<bool> usednode(n + 1 , 0) ;
vct<bool> usedan(n + 1 , 0) ;
priority_queue<ll , vct<ll> , greater<ll> > q ;
rep(i , 1 , n){
ll tmp = find(i) ;
if(!usedan[tmp]){
q.push(tmp) ;
usednode[i] = 1 ;
usedan[tmp] = 1 ;
}
}
while(q.size()){
ll now = q.top() ;
q.pop() ;
Ans.pb(now) ;
for(auto nxt : eg[now]){
if(usednode[nxt]) continue ;
q.push(nxt) ;
usednode[nxt] = 1 ;
}
}
cout << ans << "\n" ;
for(int i = 0 ; i < Ans.size() - 1 ; i ++ ) cout << Ans[i] << " " ;
cout << Ans[Ans.size() - 1] << "\n" ;
}//code_by_tyrii
小结:
又一次碰到“超级源点”。
标签:fu,fv,ll,fa,vct,2019,find,浙江省 来源: https://www.cnblogs.com/tyriis/p/16123291.html