G. MinOr Tree

G. MinOr Tree

1)题目大意:

n点m条边,做一颗生成树,使所有边的or结果最小。

2)思路:

没什么想法,请教大佬阿伟时候小悟了一波。

先将所有边放入集合。从高位到低位枚举二进制位。

1)如果可以用集合内的该二进制位为0的边构造出一个连通的,那么答案中就不用加该二进制位。

并且在遍历完边后要将没有用到的边移出集合。(这就是为什么不是去构造一棵树,而是构造一个图。最后集合中留下的是最小的可以构建出最小或树的图)

2)如果构造不出来,那么就是说必须要用该二进制位为1的边,答案就需要加上该二进制位。

3)代码:
ll n , m ; 
ll fa[N] , vis[N] ;
struct edge{
	ll u , v , w ;
	bool usin ;
}eg[N] ;

ll find(ll x){
	return fa[x] = fa[x] == x ? x : find(fa[x]) ;
}

void solve(){
	ll ans = 0 ;
	cin >> n >> m ;
	
	for(int i = 1 ; i <= n ; i ++ ) fa[i] = i ;
	
	for(int i = 1 ; i <= m ; i ++ ){
		cin >> eg[i].u >> eg[i].v >> eg[i].w ;
		eg[i].usin = 1 ;
	}
	
	for(int i = 30 ; i >= 1 ; i -- ){
		for(int j = 1 ; j <= n ; j ++ )fa[j] = j ;
		for(int j = 1 ; j <= m ; j ++ )vis[j] = 0 ;
		ll num = n ;

		for(int j = 1 ; j <= m ; j ++ ){
			//cout << (eg[j].w & (1LL << i)) << "<\n" ;
			if(!eg[j].usin || (eg[j].w & (1LL << (i - 1))) != 0) continue ;
			vis[j] = 1 ;
			ll fu = find(eg[j].u) ;
			ll fv = find(eg[j].v) ;
			if(fu != fv){
				num -- ;
				fa[fu] = fv ;
			}
		}
		//show1(fa , n) ;
		if(num != 1) ans += (1LL << (i - 1)) ;
		else{//可以用构造出0树 
			for(int j = 1 ; j <= m ; j ++ )
				if(!vis[j])eg[j].usin = 0 ; 
		}
		//cout << "i=" << i << ",num=" << num << " " << ans << "\n" ;
	}
	cout << ans << "\n" ;
}
4)附上大佬代码:

jiangly nb!!!

原文链接: https://www.cnblogs.com/tyriis/p/15793236.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    G. MinOr Tree

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/185165

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 上午10:52
下一篇 2023年2月12日 上午10:52

相关推荐