题意:现在是流感发病时期,学校有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);
}
}