The Suspects POJ - 1611

The Suspects

题目:编号为0的人有传染病,同组中只要有一个人有传染病,该组的人都被看做有传染病,一个人可以在多组中,问有多少人有传染病。

思路:并查集,需要压缩并查集的树,编号小的点优先作为祖先(0为root),并查集过程中传递祖先的同时传递祖先是否是病人,最后再次遍历所有人,使得祖先是病人子孙不是病人的情况解决,因为我们压缩了并查集的树,所以这个过程的复杂度不高。

 1 #include 
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 #include 
 7 
 8 using namespace std;
 9 
10 #define ll long long
11 #define pb push_back
12 #define fi first
13 #define se second
14 
15 const int N = 3e4 + 10;
16 bool vis[N];
17 int n, m;
18 
19 struct node{
20     int root, vis;
21 }fa[N];
22 
23 pair<int ,int > Find(int now){
24     if(fa[now].root == now){
25         //传递祖先和病人信息
26         return make_pair(fa[now].root, fa[now].vis);
27     }else{
28         pair<int ,int > tmp = Find(fa[now].root);
29         fa[now].root = tmp.fi;
30         fa[now].vis = tmp.se;
31         return tmp;
32     }
33 }
34 
35 void Union(int x, int y)
36 {
37     int fax = Find(x).fi;
38     int fay = Find(y).fi;
39     //编号小的人作为祖先
40     if(fax > fay) swap(fax, fay);
41     fa[fay].root = fax;
42 }
43 
44 
45 void solve()
46 {
47     while(~scanf("%d%d", &n, &m) && n + m){
48         for(int x = 0; x < n; ++x){
49             fa[x].root = x;
50             fa[x].vis = 0;
51         }
52         fa[0].vis = 1;
53         int num, idx, idy;
54         for(int x = 0; x < m; ++x){
55             scanf("%d%d", &num, &idx);
56 
57             for(int y = 1; y < num; ++y){
58                 scanf("%d", &idy);
59                 Union(idx, idy);
60             }
61         }
62 
63         //再次传递病人信息
64         for(int i = 0; i < n; ++i){
65             Find(i);
66         }
67 
68         int suspects = 0;
69         for(int x = 0; x < n; ++x){
70             if(fa[x].vis) ++suspects;
71         }
72 
73         //printf("suspects = %d\n", suspects);
74         printf("%d\n", suspects);
75     }
76 }
77 
78 int main()
79 {
80 
81     solve();
82 
83     return 0;
84 }

 

你可能感兴趣的:(The Suspects POJ - 1611)