CF 1624G - MinOr Tree

题目链接:

https://codeforces.com/problemset/problem/1624/G

题目大意:

一棵 \(spanning tree\) 的 \(ority\) 就是它所有边权的位或值,现在给出一个图,求出里面 \(spanning tree\) 的 \(ority\) 的最小值,\(spanning tree\) 就是一个无环的连通子图。

思路:

刚开始看到题目的时候,第一时间想到的是最小生成树,每次添加一条最小的边到已知集合中,但是这个最小不好判断。于是反过来考虑,从“避圈法”改为“破圈法”。
因为要求最小的位或值,所以我们可以枚举二进制的每一位,去除掉该位为 1 的边,剩下的如果是连通图,那么该位就可以去掉,通过这种方式去去掉边。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 2e5 + 10;
LL T = 1, n, m, fa[N];
struct node{
	LL u, v, w;
}e[N];
LL find(LL x){
	if (fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}
void join(LL a, LL b){
	fa[find(b)] = find(a);
}
bool judge(LL x){
	for (int i = 1; i <= n; i++)
		fa[i] = i;
	for (int i = 1; i <= m; i++){
		if (e[i].w & x) continue;
		join(e[i].u, e[i].v);
	}
	for (int i = 2; i <= n; i++)
		if (find(fa[i]) != find(fa[i - 1]))
			return false;
	return true;
}
void solve(){
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= m; i++)
		scanf("%lld%lld%lld", &e[i].u, &e[i].v, &e[i].w);
	LL res = 0;
	for (int bit = 29; bit >= 0; bit--){
		LL cur = res + (1LL << bit);
		if (judge(cur))
			res += (1LL << bit);
	}
	cout << (1LL << 30) - 1 - res << "\n";
}
int main(){
	cin >> T;
	while (T--)
		solve();
	return 0;
}
上一篇:【C#】实现链表


下一篇:【每日编程09】移除重复节点和打印链表