题意:n点,m边,边有权值,求最大生成树,权值为所有边的‘&’运算。
思想:110010&100=100,小于等于最小的数,所有的边‘&’运算后会得到一个权值w,那么w写成二进制后,假设为100110,那么这个在所有的被选中的边都应该存在这一部分(不是完全一样,注意1的位置),那么就可以从30位开始枚举每一位,如过第k位是1的所有边可以构成一个生成树是,那么就选择这一位,如过没有就跳过,找出所有的位置就可以了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,mark[300000+50],father[300000+50];
struct node
{
int u,v,w;
}e[300000+50];
int find(int x)
{
if(x!=father[x])
father[x]=find(father[x]);
return father[x];
}
void union_set(int a,int b)
{
a=find(a);
b=find(b);
if(a!=b) father[a]=b;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
int ans=0;
for(int i=30;i>=0;i--)
{
for(int j=1;j<=n;j++)
father[j]=j;
for(int j=1;j<=m;j++)
{
if(((e[j].w&ans)==ans)&&(e[j].w>>i&1))
mark[j]=1;
else mark[j]=0;
}
for(int j=1;j<=m;j++)
{
if(mark[j]) union_set(e[j].u,e[j].v);
}
int falg=1,k=find(1);
for(int j=2;j<=n;j++)
{
if(find(j)!=k)
{
falg=0;
break;
}
}
if(falg) ans|=(1<<i);
}
printf("%d\n",ans);
}
return 0;
}