1. 程式人生 > 其它 >POJ 1611 - The Suspects - Union-Find

POJ 1611 - The Suspects - Union-Find

POJ 1611 - The Suspects

描述
嚴重急性呼吸系統綜合症(SARS)是一種病因不明的非典型肺炎,在2003年3月中旬被確認為全球性威脅。
為了儘量減少對他人的傳播,最好的策略是將疑似者與其他人分開。
在不傳播疾病的大學(NSYSU)中,有很多學生群體。同一組的學生經常互相交流,一個學生可以加入幾個組。
為了防止非典型肺炎的傳播,NSYSU收集了所有學生團體的成員名單,並在其標準操作程式(SOP)中制定了以下規則:
一旦一個小組的成員是疑似者,這個小組的所有成員都是疑似者。
然而,他們發現,當一個學生被認定為疑似者時,要找出所有的疑似者並不容易。你的工作是寫一個程式找出所有疑似者。

輸入


輸入檔案包含幾個案例。每個測試用例從一行中的兩個整數n和m開始,其中n是學生數,m是組數。
你可以假設0<n<=30000和0<=m<=500。每個學生都用一個介於0和n−1之間的唯一整數來編號,最初學生0被認為是所有案件的疑似者。
這一行後面是m個組的成員列表,每個組一行。每一行都以一個整數k開始,表示組中的成員數。在成員數之後,有k個整數代表這個組中的學生。
一行中的所有整數至少用一個空格隔開。
n=0且m=0的case表示輸入結束,不需要處理。

輸出
對於每個案例,輸出一行中的疑似者數量。

思路: 並查集
1:一個組內只要有人疑似,就整組疑似,所以同組的合併;
2:用陣列記錄疑似個數,合併的時候,個數累加;


3:合併時小點往大點上合併,所以大點的個數包含所有子節點的個數;
4:只為0號已被認為是疑似者,所以要求所有涉及0的點的個;
5:由於從小到大合併,同組內,最大節點就是0的根節點,且該點個數包含此組所有人數,該根節點再往上找,可找到它所涉及的所有點的根節點,此點的個數,即為最終答案;
6:find(0)是從0開始一層層找到根節點,即最大的節點,suspectCnt[find(0)]是最大點的個數,即為所有疑似者個數

package basic_data_structure;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/**
 * @author XA-GDD
 *
 ** 思路: 並查集, 
 *	1:一個組內只要有人疑似,就整組疑似,所以同組的合併;
 *	2:用陣列記錄疑似個數,合併的時候,個數累加;
 *	3:合併時小點往大點上合併,所以大點的個數包含所有子節點的個數;
 *	4:只為0號已被認為是疑似者,所以要求所有涉及0的點的個;
 *	5:由於從小到大合併,同組內,最大節點就是0的根節點,且該點個數包含此組所有人數,該根節點再往上找,可找到它所涉及的所有點的根節點,此點的個數,即為最終答案;
 *	6:find(0)是從0開始一層層找到根節點,即最大的節點,suspectCnt[find(0)]是最大點的個數,即為所有疑似者個數
 *  
 */
public class D_TheSuspects {

	static int N,M,K;
	static int _Max_Size = 30005;
	static int [] parent = new int[_Max_Size];;
	static int [] suspectCnt = new int[_Max_Size];;
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;  
        StringTokenizer st;
		while((str = br.readLine()) != null) {
			st = new StringTokenizer(str);
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			if(N==0 && M==0)	break;
				
			for(int i=0;i<N;i++) {
				parent[i] = i;
				suspectCnt[i] = 1;
			}
			
			for(int i=0;i<M;i++) {
				st = new StringTokenizer(br.readLine());
				K = Integer.parseInt(st.nextToken());
				
				int firstNo = Integer.parseInt(st.nextToken()); 
				for(int j=1;j<K;j++) { 
					int nextNo = Integer.parseInt(st.nextToken()); 
					union(firstNo,nextNo);
				}
			}
			System.out.println(suspectCnt[find(0)]);
		}
	}
	
	static void union(int a, int b) {
		int pa = find(a);
		int pb = find(b);
		if(pa==pb)	return;
		if(pa>pb) {
			parent[pb] = pa;
			suspectCnt[pa]  += suspectCnt[pb];
		}else{
			parent[pa] = pb;
			suspectCnt[pb]  += suspectCnt[pa];
		}			
	}
	
	static int find(int n) {
		if(parent[n]==n)	return n;
		return parent[n] = find(parent[n]);
	}
	 
}