POJ1611 The Suspects

    原题链接:http://poj.org/problem?id=1611

    并查集。在每个group中,最开始的出发点是以该group中最小编号的学生为根的(这个是根据题意编号为0的学生是suspect来决定的),如果该group中有某个学生的父亲节点(或祖父节点)编号大于该group最小编号,则将最小编号union到上述的父亲节点(或祖父节点)上,那么在处理完成后,可以构造出一颗以编号0学生为根的树(并查集)。对所有节点询问其祖先节点,如果其祖先节点编号为0,那么计数加1。

View Code
 1 #include <stdio.h>
 2 #include <algorithm>
 3 #define N 30010
 4 #define INF 0x3f3f3f3f
 5 int f[N], a[N];
 6 
 7 int find(int x)
 8 {
 9     return x == f[x] ? f[x] : f[x] = find(f[x]);
10 }
11 
12 inline void MakeSet()
13 {
14     for(int i = 0; i < N; i ++)
15         f[i] = i;
16 }
17 
18 int main()
19 {
20     int i, j, k, n, m, cnt;
21     while(scanf("%d%d", &n, &m), (n || m))
22     {
23         MakeSet();
24         while(m --)
25         {
26             scanf("%d", &k);
27             for(i = 0; i < k; i ++)
28                 scanf("%d", &a[i]);
29             std::sort(a, a + k);
30             for(i = 1; i < k; i ++)
31             {
32                 j = f[a[i]]; 
33                 if(j != a[i])   // 如果条件成立,那么a[i]已经属于某棵树
34                 {
35                     if(f[j] < f[a[0]])   // a[i]的元祖先与当前祖先比较,将较大的祖先合并到较小的祖先
36                         f[a[0]] = f[j];
37                     else
38                         f[j] = f[a[0]];
39                 }
40                 else
41                     f[a[i]] = f[a[0]];
42             }
43         }
44         for(cnt = i = 0; i <= n; i ++)
45         {
46             j = find(i);
47             if(j == 0)
48                 cnt ++;
49         }
50         printf("%d\n", cnt);
51     }
52     return 0;
53 }

 

 

你可能感兴趣的:(poj)