POJ1611 The Suspects
原题链接:http://poj.org/problem?id=1611
并查集。在每个group中,最开始的出发点是以该group中最小编号的学生为根的(这个是根据题意编号为0的学生是suspect来决定的),如果该group中有某个学生的父亲节点(或祖父节点)编号大于该group最小编号,则将最小编号union到上述的父亲节点(或祖父节点)上,那么在处理完成后,可以构造出一颗以编号0学生为根的树(并查集)。对所有节点询问其祖先节点,如果其祖先节点编号为0,那么计数加1。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }