题目地址:
http://poj.org/problem?id=1611
/************************************************************************
大致题意:一共有n个学生(编号0 至 n-1),m个组,一个学生可以同时加入不同的组。
现在有一种传染病,如果一个学生被感染,那么和他同组的学生都会被感染。现在已
知0号学生被感染,问一共有多少个人被感染。
首先将每个学生都初始化为一个集合,然后将同组的学生合并,设置一个数组num[]
来记录每个集合中元素的个数,最后只要输出0号学生所在集合中元素的个数即可。
**************************************************************************/
View Code
1 #include<iostream>
2 usingnamespace std;
3 //num[]数组存储节点所在的集合的总个数
4 //father[]数组存储dina
5 int num[30001],father[30001];
6 //初始化用,把每一个点定义为一个集合
7 void makeSet(int x){
8 father[x]=x;//定义跟节点的标志:即为与父亲数组的值相同
9 num[x]=1;
10 }
11 /**********************************************************/
12 //查找x元素所在的集合,返回根节点
13 //并且采用递归方式压缩路径,使得每一个点都指向根节点
14 int findSet(int x){
15 if(x!=father[x])//只有根节点的父亲节点才与自己的值相同
16 x=findSet(father[x]);
17 return x;//此时的x已经被层层修改为最根的那个节点
18 }
19 void unionSet(int a,int b){
20 a = findSet(a);
21 b = findSet(b);
22 if(a==b)return;//在同一个集合中,直接退出
23 //此if,else语句将小集合合并到大集合中
24 //用来平衡树的左右形状,减少整体层数
25 if(num[a]<=num[b]){
26 father[a]=b;
27 num[b]+=num[a];//更新集合的个数
28 }
29 else{
30 father[b]=a;
31 num[a]+=num[b];
32 }
33 }
34
35 int main(){
36 int m,n;
37 while(cin>>m>>n&&(m!=0||n!=0)){
38 for(int i=0;i<m;i++)makeSet(i);
39 int t,first,next;
40 while(n--){
41 cin>>t>>first;
42 for(int j=1;j<t;j++){
43 cin>>next;
44 unionSet(first,next);
45 }
46 }
47 cout<<num[findSet(0)]<<endl;
48 }
49 return0;
50 }
51