Welcome Party(并查集 启发式合并)

原题: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6011

抛开zoj的问题,如果要百分百过的话(不被数据制裁),需要用到启发式合并。即每次将小的连到大的连通块,这样得出的结构一定是log级别层数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000005;
int fa[maxn],mi[maxn],head[maxn];
int siz[maxn];
int Ans[maxn],cnt,ans;
bool vis[maxn];
struct edge{
    int to,nex;
}e[maxn<<1];
void add(int u,int v){
    e[cnt].to=v,e[cnt].nex=head[u];
    head[u]=cnt++;
}
int fin(int x){
    return fa[x]==x?x:fa[x]=fin(fa[x]);
}
priority_queue<int,vector<int>,greater<int> > Q;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            head[i]=-1;
            fa[i]=i;
            siz[i]=1;
            mi[i]=i;
            vis[i]=0;
        }
        for(int i=1;i<=m;i++){
            int a,b; scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
            int f1=fin(a),f2=fin(b);
            if(f1!=f2){
                if(siz[f1]>siz[f2])swap(f1,f2);
                fa[f1]=f2;
                mi[f2]=min(mi[f1],mi[f2]);
                siz[f2]+=siz[f1];
            }
        }
        ans=0;
        for(int i=1;i<=n;i++){
            if(fin(i)==i){
                ans++;
                Q.push(mi[i]);
                vis[mi[i]]=1;
            }
        }

        int now=0;
        while(!Q.empty()){
            int p=Q.top();Q.pop();
            Ans[++now]=p;
            for(int i=head[p];i!=-1;i=e[i].nex){
                int to=e[i].to;
                if(vis[to]) continue;
                Q.push(to);
                vis[to]=1;
            }
        }
        printf("%d\n",ans);
        for(int i=1;i<=now;i++){
            printf("%d%c",Ans[i],(i==now?'\n':' '));
        }
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/89637289
今日推荐