hdoj Clarke and MST 5627(求位运算and后得到的最大生成树)(并查集&位运算)好题

211 篇文章 1 订阅
32 篇文章 1 订阅

Clarke and MST

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 421    Accepted Submission(s): 233


Problem Description
Clarke is a patient with multiple personality disorder. One day he turned into a learner of graph theory.  
He learned some algorithms of minimum spanning tree. Then he had a good idea, he wanted to find the maximum spanning tree with bit operation AND.  
A spanning tree is composed by   n1  edges. Each two points of   n  points can reach each other. The size of a spanning tree is generated by bit operation AND with values of   n1  edges.  
Now he wants to figure out the maximum spanning tree.
 

Input
The first line contains an integer   T(1T5) , the number of test cases.  
For each test case, the first line contains two integers   n,m(2n300000,1m300000) , denoting the number of points and the number of edge respectively.  
Then   m  lines followed, each line contains three integers   x,y,w(1x,yn,0w109) , denoting an edge between   x,y  with value   w .  
The number of test case with   n,m>100000  will not exceed 1.  
 

Output
For each test case, print a line contained an integer represented the answer. If there is no any spanning tree, print 0.
 

Sample Input
  
  
1 4 5 1 2 5 1 3 3 1 4 2 2 3 1 3 4 7
 

Sample Output
  
  
1
问题描述
克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。  
他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算and的最大生成树。  
一棵生成树是由n-1n1条边组成的,且nn个点两两可达。一棵生成树的大小等于所有在生成树上的边的权值经过位运算and后得到的数。  
现在他想找出最大的生成树。
输入描述
第一行是一个整数T(1 \le T \le 5)T(1T5),表示数据组数。  
每组数据第一行是两个整数n, m(1 \le n, m \le 300000)n,m(1n,m300000),分别表示点个数和边个数。其中n, m > 100000n,m>100000的数据最多一组。  
接下来mm行,每行33个整数x, y, w(1 \le x, y \le n, 0 \le w \le 10^9)x,y,w(1x,yn,0w109),表示x, yx,y之间有一条大小为ww的边。
输出描述
每组数据输出一行一个数,表示答案。若不存在生成树,输出00
输入样例
1
4 5
1 2 5
1 3 3
1 4 2
2 3 1
3 4 7
输出样例
1
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define ING 0x3f3f3f3f
#define ll long long
#define N 300010
using namespace std;
struct zz
{
	int u;
	int v;
	int w;
}p[N];
int f[N];
int n,m;
int find(int x)
{
	return x==f[x]?x:f[x]=find(f[x]);
}
int judge(int x)
{
	int i,j;
	for(i=1;i<=n;i++)
		f[i]=i;
	for(i=0;i<m;i++) 
	{
		if((p[i].w&x)==x)//如果加入第i条边后不影响结果,则将这条边加入这棵树 
		{
			int fx=find(p[i].u);
			int fy=find(p[i].v);
			if(fx!=fy)
				f[fx]=fy;
		}
	}
	int cnt=0,k=find(1);
	for(i=2;i<=n;i++)//判断加入进去的边是否组成一颗树。 
		if(find(i)!=k)
			return 0;
	return 1;
}
int main()
{
	int t,i,j;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(i=0;i<m;i++)
			scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
		int ans=0;
		for(i=31;i>=0;i--)//枚举所有答案 
		{
			int tmp=ans|(1<<i);
			if(judge(tmp))
				ans=tmp;
		}
		printf("%d\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值