B - The Suspects(并查集)
B - The Suspects
Time Limit:1000MS Memory Limit:20000KB 64bit IO Format:%lld & %lluDescription
严重急性呼吸系统综合症( SARS), 一种原因不明的非典型性肺炎,从2003年3月中旬开始被认为是全球威胁。为了减少传播给别人的机会, 最好的策略是隔离可能的患者。
在Not-Spreading-Your-Sickness大学( NSYSU), 有许多学生团体。同一组的学生经常彼此相通,一个学生可以同时加入几个小组。为了防止非典的传播,NSYSU收集了所有学生团体的成员名单。他们的标准操作程序(SOP)如下:
一旦一组中有一个可能的患者, 组内的所有成员就都是可能的患者。
然而,他们发现当一个学生被确认为可能的患者后不容易识别所有可能的患者。你的工作是编写一个程序, 发现所有可能的患者。
Input
输入文件包含多组数据。
对于每组测试数据:
第一行为两个整数n和m, 其中n是学生的数量, m是团体的数量。0 < n <= 30000,0 <= m <= 500。
每个学生编号是一个0到n-1之间的整数,一开始只有0号学生被视为可能的患者。
紧随其后的是团体的成员列表,每组一行。
每一行有一个整数k,代表成员数量。之后,有k个整数代表这个群体的学生。一行中的所有整数由至少一个空格隔开。
n = m = 0表示输入结束,不需要处理。
Output
对于每组测试数据, 输出一行可能的患者。
Sample Input
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0
Sample Output
4
1
1
//初学并查集,第二周训练第一个完全没百度做出来的,中规中矩的,虽然过了但是用了 352KB 922ms,好险。以后有机会更新优化。
1 #include <iostream>
2 #include <cstdio>
3 using namespace std;
4
5 const int N=30005;
6 int set_tree[N];
7 int person[N];
8 bool flag[N];
9
10 void Init ()
11 {
12 for (int i=0;i<N;i++)
13 {
14 set_tree[i]=i;
15 flag[i]=0;
16 }
17 }
18
19 int find_head(int x)
20 {
21 while (x!=set_tree[x]) x=set_tree[x];
22 return x;
23 }
24
25 void link(int x,int y)
26 {
27 x=find_head(x);
28 y=find_head(y);
29 if (x==y) return;
30 set_tree[x]=set_tree[y];
31 }
32
33 void hebing(int p)
34 {
35 int i;
36 for (i=0;i<p-1;i++)//合并p个人.0.1,1.2,......,p-2.p-1 合并
37 {
38 link(person[i],person[i+1]);
39 }
40 }
41
42 int main()
43 {
44 int n,m,p,i,all;
45 Init();
46 while (scanf("%d%d",&n,&m))
47 {
48 if (n==0&&m==0) break;
49 Init();
50 all=1;
51 while (m--)
52 {
53 scanf("%d",&p);
54 for (i=0;i<p;i++)
55 {
56 scanf("%d",&person[i]);
57 flag[person[i]]=1;
58 }
59 hebing(p);
60 }
61
62 for (i=1;i<n;i++)
63 {
64 if (flag[i]==1&&find_head(i)==find_head(0))
65 all++;
66 }
67 printf("%d\n",all);
68
69 }
70 return 0;
71 }
//原来要路径压缩 468k 16ms
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 const int N=30005; 6 int f[N]; 7 int person[N]; 8 bool flag[N]; 9 10 void Init () 11 { 12 for (int i=0;i<N;i++) 13 { 14 f[i]=i;//并查集初始化 15 flag[i]=0; 16 } 17 } 18 19 int find_head(int x) 20 { 21 if (x!=f[x]) 22 f[x]=find_head(f[x]); 23 return f[x]; 24 } 25 26 void link(int x,int y) 27 { 28 x=find_head(x); 29 y=find_head(y); 30 if (x==y) return; 31 f[x]=f[y]; 32 } 33 34 int main() 35 { 36 int n,m,p,i,j,all; 37 Init(); 38 while (scanf("%d%d",&n,&m)) 39 { 40 if (n==0&&m==0) break; 41 Init(); 42 43 all=1;// 一开始 0 号就是患者 44 45 while (m--) 46 { 47 scanf("%d",&p); 48 for (i=0;i<p;i++) 49 { 50 scanf("%d",&person[i]); 51 flag[person[i]]=1; 52 } 53 for (j=0;j<p-1;j++)//合并p个人.0.1,1.2,......,p-2.p-1 合并 54 link(person[j],person[j+1]); 55 } 56 57 for (i=1;i<n;i++) 58 { 59 if (flag[i]==1&&find_head(i)==find_head(0)) 60 all++; 61 } 62 printf("%d\n",all); 63 64 } 65 return 0; 66 }