Clarke and MST
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 282 Accepted Submission(s): 157
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
Source
BestCoder Round #72 (div.2)
题意是需要找到一棵生成树使得树上的&和最大。
拆位,从最大位开始依次判断这个位上为1的那些边能不能组成一棵ST,如果可以就更新边集,复杂度O(32*n)。
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <time.h>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 311111
#define maxm 611111
struct node {
int u, v;
long long w;
};
vector <node> edge[2];
int n, m;
int fa[maxn];
int find (int x) {
return fa[x] == x ? fa[x] : fa[x] = find (fa[x]);
}
bool ok (int id) { //判断能不能构成一个联通分量
for (int i = 1; i <= n; i++)
fa[i] = i;
int Max = edge[id].size ();
for (int i = 0; i < Max; i++) {
int u = edge[id][i].u, v = edge[id][i].v;
int p1 = find (u), p2 = find (v);
if (p1 != p2)
fa[p1] = p2 ;
}
int gg = find (1);
for (int i = 2; i <= n; i++) {
if (find (i) != gg)
return 0;
}
return 1;
}
bool is_1 (long long num, int id) { //判断num的id位是不是1
id--;
num >>= id;
return (num&1);
}
bool work (int id) { //判断id位能否为1
int Max = edge[0].size ();
for (int i = 0; i < Max; i++) {
if (is_1 (edge[0][i].w, id)) {
edge[1].push_back (edge[0][i]);
}
}
if (ok (1)) {
edge[0].clear ();
int Max = edge[1].size ();
for (int i = 0; i < Max; i++) {
edge[0].push_back (edge[1][i]);
}
return 1;
}
return 0;
}
int main () {
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d%d", &n, &m);
edge[0].clear (); edge[1].clear ();
for (int i = 1; i <= m; i++) {
int u, v; long long w;
scanf ("%d%d%lld", &u, &v, &w);
edge[0].push_back ((node){u, v, w});
}
if (!ok (0)) {
printf ("0\n");
continue;
}
long long ans = 0;
for (int i = 32; i >= 1; i--) {
edge[1].clear ();
if (work (i)) {
ans <<= 1;
ans++;
}
else
ans <<= 1;
}
printf ("%lld\n", ans);
}
return 0;
}