其他分享
首页 > 其他分享> > 2019浙江省赛 - J

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