bestcoder #71 1003 找位运算&的最大生成树

Clarke and MST

 
 Accepts: 33
 
 Submissions: 92
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。  
他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算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
这是一道好题,可惜我太笨,比赛的时候没做出来,虽然并不难。。。
从大到小枚举位数i,如果能生成树,那么该位的生成树MST(i)一定是前一位+(1<<i),当然对树上所有的边还要满足MST(i)&w==MST(i).
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n,m;
struct Edge
{
    int u,v;
    ll w;
};Edge e[maxn];
int fa[maxn];
int u,v;
ll w;

int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}

void solve(ll t,ll &ans)
{
    REP(i,1,n) fa[i]=i;
    ans+=t;
    REP(i,1,m){
        u=e[i].u,v=e[i].v,w=e[i].w;
        int x=find(u),y=find(v);
        if(x!=y&&((w&ans)==ans)) fa[x]=y;
    }
    int st=find(1);
    REP(i,2,n){
        if(find(i)!=st){
            ans-=t;return;
        }
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int T;cin>>T;
    while(T--){
        scanf("%d%d",&n,&m);
        REP(i,1,m){
            scanf("%d%d%I64d",&u,&v,&w);
            e[i]=(Edge){u,v,w};
        }
        ll ans=0;
        for(int i=32;i>=0;i--){
            solve(1LL<<i,ans);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

 

你可能感兴趣的:(bestcoder #71 1003 找位运算&的最大生成树)