并查集-HDU-5627-Clarke and MST

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;
}

你可能感兴趣的:(c,并查集)