Clarke and MST
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 342 Accepted Submission(s): 191
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 n−1 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 n−1 edges.
Now he wants to figure out the maximum spanning tree.
Input
The first line contains an integer T(1≤T≤5), the number of test cases.
For each test case, the first line contains two integers n,m(2≤n≤300000,1≤m≤300000), denoting the number of points and the number of edge respectively.
Then m lines followed, each line contains three integers x,y,w(1≤x,y≤n,0≤w≤109), 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
Source
BestCoder Round #72 (div.2)
题意:
克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。
他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算and的最大生成树。
一棵生成树是由n−1条边组成的,且n个点两两可达。一棵生成树的大小等于所有在生成树上的边的权值经过位运算and后得到的数。
现在他想找出最大的生成树。
题解:
首先我们得分析位运算与的特征,很明显,与运算和运算顺序没有关系,不像异或(那样这题就没得做了),那么要求一个生成树的与结果最大,就是所有边权在二进制相应位下都为1,那么就按位来一个枚举,从最大位开始,依次枚举2的倍数tmp,只有和tmp的与运算等于tmp的边权才是合法边,再验证是否能在合法边中找到生成树,如果能,就将这个tmp记录下来成为now,之后的tmp都要或(位运算)上这个now,最后枚举到1结束,输出当前now。
验证是否能够找到生成树就直接用并查集,所以我将此题划分到了并查集一类,个人这个根本不算什么最大生成树的题。
//
// main.cpp
// BestCoder-Round 72.2-3
//
// Created by 袁子涵 on 16/2/13.
// Copyright © 2016年 袁子涵. All rights reserved.
//
// 327ms 8864KB
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <cstdlib>
#define MAXN 300005
using namespace std;
int t;
long long int n,m,now,tmp;
typedef struct {
long long int x,y,w;
}Edge;
Edge E[MAXN];
long long int father[MAXN];
long long int find(long long int x)
{
long long int s=x,root,tem;
while (father[s]!=s)
s=father[s];
root=s;
s=x;
while (father[s]!=s) {
tem=father[s];
father[s]=root;
s=tem;
}
return root;
}
int main(int argc, char *argv[])
{
scanf("%d",&t);
while (t--) {
scanf("%lld%lld",&n,&m);
for (long long int i=1; i<=m; i++)
scanf("%lld%lld%lld",&E[i].x,&E[i].y,&E[i].w);
now=0;
for (int i=31; i>=0; --i) {
tmp=now | (1<<i);
for (long long int j=1; j<=n; j++)
father[j]=j;
for (long long int j=1; j<=m; j++) {
if ((tmp & E[j].w)==tmp)
if (find(E[j].x)!=find(E[j].y))
father[father[E[j].x]]=father[E[j].y];
}
long long int sum=0;
for (long long int j=1; j<=n; j++)
if (father[j]==j)
sum++;
if (sum==1)
now=tmp;
}
printf("%lld\n",now);
}
return 0;
}