#454. Minimum Or Spanning Tree
#454. Minimum Or Spanning Tree
题目描述
给出\(n\)个点, \(m\)条边的无向图, 每条边连接\(u,v\)两个端点,边权为\(w\), 求图的生成树的最小代价。
在这道题中, 我们定义一棵生成树的代价为他所有边的边权按位或得到的值。
输入格式
第一行两个数字 \(n\) 和 \(m , n\) 表示点数,$m $表示图的边数。
接下来 \(m\) 行 , 每行三个整数 \(u,v,w\),表示点 \(u\) 和点\(v\) 之间存在一条边权为 \(w\) 的边。
输出格式
一行, 描述生成树的最小代价。
样例输入
5 7
4 2 7
2 5 8
3 4 2
3 2 1
2 4 2
4 1 2
1 2 2
样例输出
10
数据规模
所有数据保证 \(1≤u,v≤n≤2⋅10^5,n−1≤m≤4⋅10^5,1≤w≤10^9\)且至少存在一棵生成树。
题目分析
先假设\(ans\)为最大值,按位枚举看看当前位是否能为\(0\),把为\(0\)的放在一起,通过并查集检测是否构成联通图。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+7;
struct Edge {
ll s,f;
ll val;
};
inline int read(){
int This=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') F=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
This=(This<<1)+(This<<3)+ch-'0';
ch=getchar();
}
return This*F;
}
int fa[N];
inline int find(int x) {
if(x==fa[x])
return x;
fa[x] = find(fa[x]);
return fa[x];
}
inline void unoin(Edge x) {
ll x_fa = find(x.s);
ll y_fa = find(x.f);
fa[x_fa] = y_fa;
}
inline bool check(int n) {
int t = find(1);
for(int i = 1 ; i <= n ; i++)
if(find(i)!=t)
return 0;
return 1;
}
int main() {
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
vector<Edge>e;
for(int i = 1 ; i <= m ; i++) {
ll s = read(),f= read(),val= read();
e.push_back({s,f,val});
}
ll ans = (1ll<<32)-1;
for(int i = 31 ; i>=0 ; i--) {
ans -= (1ll<<i);
vector<Edge>te;
memset(fa,0,sizeof(fa));
for(int i = 1 ; i <= n ; i++)
fa[i] = i;
for(int j = 0 ; j < e.size() ; j++) {
if((e[j].val | ans) <= ans) { //希望筛出该位为0
te.push_back(e[j]);
unoin(e[j]);
}
}
if(check(n))
e = te;
else ans += (1ll<<i);
}
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号