Clarke and MST
Accepts: 33
Submissions: 92
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。 他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算and的最大生成树。 一棵生成树是由n−1条边组成的,且n个点两两可达。一棵生成树的大小等于所有在生成树上的边的权值经过位运算and后得到的数。 现在他想找出最大的生成树。
输入描述
第一行是一个整数T(1≤T≤5),表示数据组数。 每组数据第一行是两个整数n,m(1≤n,m≤300000),分别表示点个数和边个数。其中n,m>100000的数据最多一组。 接下来m行,每行3个整数x,y,w(1≤x,y≤n,0≤w≤109),表示x,y之间有一条大小为w的边。
输出描述
每组数据输出一行一个数,表示答案。若不存在生成树,输出0。
输入样例
1 4 5 1 2 5 1 3 3 1 4 2 2 3 1 3 4 7
输出样例
1
我们知道kruskal算法中,用并查集+结构体排序就能得到所求最小生成树的权值和,所以我们这里也可以使用kruskal算法来形成最大生成树
在sort的时候把最小值优先改为最大值优先,并且判断一共连接的边是n-1条就行了:
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct path
{
int u,v,val;
}a[300006];
int f[300006];
int find(int x)
{
return f[x] == x ? x : (f[x] = find(f[x]));
}
int cmp(path a,path b)
{
return a.val>b.val;
}
void merge(int a,int b)
{
int A,B;
A=find(a);
B=find(b);
if(A!=B)
f[B]=A;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
f[i]=i;
}
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].val);
}
sort(a,a+m,cmp);
int ans;
int f=0;
int num=n-1;
for(int i=0;i<m;i++)
{
if(find(a[i].u)!=find(a[i].v))
{
if(f==0)
{
f=1;
merge(a[i].u,a[i].v);
ans=a[i].val;
num--;
continue;
}
else
{
merge(a[i].u,a[i].v);
ans&=a[i].val;
}
num--;
}
}
if(num==0)
{
printf("%d\n",ans);
}
else
{
printf("0\n");
}
}
}