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]);
	}
	 
}

  

posted @ 2021-10-10 09:44  晓暮云  阅读(42)  评论(0)    收藏  举报