1. 程式人生 > >【並查集】POJ1611 The Suspects

【並查集】POJ1611 The Suspects

The syn ssi separate div unit 還在 ide other

The Suspects
Time Limit: 1000MS Memory Limit: 20000K
Total Submissions: 51969 Accepted: 24829

Description

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others.
In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP).
Once a member in a group is a suspect, all members in the group are
suspects.
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.

Input

The input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n <= 30000 and 0 <= m <= 500. Every student is numbered by a unique integer between 0 and n?1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group. Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space.
A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.

Output

For each case, output the number of suspects in one line.

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


並查集經
典題。大意就是非典時期,某學校有n個學生,每個學生從0~n-1被標上號。學校有許多學生小組,如果一組中有一個學生懷疑有感染非典,那個整個小組的學生都成為懷疑對象。
現在0號學生現在是懷疑對象,給出小組信息,求有多少個學生是懷疑對象。
可以看一下並查集經典模板:
 1 //並查集的實現
 2 
 3
#define MAX_N 100 4 5 int par[MAX_N]; //父親 6 int Rank[MAX_N]; //樹的高度 7 8 //初始化n個元素 9 void init(int n){ 10 for(int i = 0; i < n; i++){ 11 par[i] = i; 12 Rank[i] = 0; 13 } 14 } 15 16 //查詢樹的根 17 int find(int x){ 18 if(par[x] == x) return x; 19 else 20 return par[x] = find(par[x]); //路徑壓縮:查詢過程中,向上經過的所有節點,都改為直接連到根上 21 } 22 23 //合並x和y所屬的集合:從一個組的根向另一個組的根連邊 24 void unite(int x,int y){ 25 x = find(x); 26 y = find(y); 27 if(x == y) return; //x和y已經是同一組的了,直接返回 28 //從高度(Rank)小的向高度大的連邊 29 if(Rank[x] < Rank[y]) //x的高度小,x向y連邊 30 par[x] = y; 31 else{ //否則,y向x連邊 32 par[y] = x; 33 if(Rank[x] == Rank[y]) Rank[x]++; //如果兩個高度一樣,合並後樹高度+1 34 } 35 } 36 37 //判斷x和y是否屬於同一個集合 38 bool same(int x,int y){ 39 return find(x) == find(y); 40 }

把模板用到這道題上,一組的學生就可以看成一棵樹,先找出和0一組的所有學生,如果這些學生還在其他組的樹中,合並這兩棵樹,最後輸出0所在樹中所有節點個數,即可得到答案。
下面給出AC代碼:
 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 int p[30005],a[30005];
 7 
 8 int find(int x){    //查詢根節點
 9     if(p[x]==x) return x;
10     else
11         return p[x] = find(p[x]); //路徑壓縮:查詢過程中,向上經過的所有節點,都改為直接連到根上
12 }
13 //合並x和y所屬的集合:從一個組的根向另一個組的根連邊
14 void unite(int a,int b){
15     int x = find(a),y = find(b);
16     if(x!=y)
17         p[y] = p[x];
18 }
19 
20 int main(){
21     int n,m,k,sum;  //n:學生數 m:組數 k:每組人數 sum:懷疑人總數
22     while(cin>>n>>m&&(n||m)){
23         sum = 0;
24         for(int i = 0;i<n;i++)
25             p[i] = i;
26         while(m--){
27             cin>>k; //每組的人數
28             cin>>a[0];
29             for(int i = 1;i<k;i++){
30                 cin>>a[i];
31                 unite(a[0],a[i]);  
32 } 33 } 34 for(int i = 0;i<n;i++){ 35 if(find(0)==find(i)) //找到同一個根節點說明在同一個樹 36 sum++; 37 } 38 cout<<sum<<endl; 39 } 40 41 return 0; 42 }

 

【並查集】POJ1611 The Suspects