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