C - The Suspects POJ - 1611 并查集的简单应用(超详细!!)

题意:现在是流感发病时期,学校有n个学生,学生编号为0~n-1,m个社团。0号学生是病毒携带者,如果有学生和病毒携带者在同一个社团,那么他也会变为病毒携带者。如  社团1(0,1 ,社团2( 1,2,3),那么 0,1,2,3都是病毒携带者。
给出学生人数和社团情况,问,有多少个病毒携带者。

思路:用并查集来合并集合就可以了,把每个社团当作一个集合和并。最后,找出0号学生所在的集合的根节点,然后遍历所有学生,如果和0号学生的根节点相同,说明他们在一个集合当中。

///仔细理解一下Find()操作!!
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include <string>
using namespace std;
int rk[30005],par[30005];
int a[30005];
int n,ans;
void init()//初始化
{
    for(int i=0;i<n;i++){
        rk[i]=0;
        par[i]=i;
    }
}
int Find(int x)//查找根节点
{
    while(x!=par[x])
        x=par[x];
    return x;
}
void unite(int x, int y)//合并集合
{
    x=Find(x);
    y=Find(y);
    if(x==y)
        return ;
    if(rk[x]<rk[y])
        par[x]=y;
    else{
        par[y]=x;
        if(rk[x]==rk[y])
            rk[x]++;
    }
}
int main()
{
    int m,x;
    int a,b;
    while(~scanf("%d%d",&n,&m)&&(n+m)){
        init();
        for(int i=0;i<m;i++){
            scanf("%d",&x);
            scanf("%d",&a);//将每个社团的第一个人当作该社团的根节点合并
            for(int j=1;j<x;j++){
                scanf("%d",&b);
                    unite(a,b);
            }
        }
        ans=1;
        for(int i=1;i<n;i++){//查找和0号学生在同一集合的学生
            if(Find(i)==Find(0))
                ans++;
        }
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41874469/article/details/80243140
今日推荐