并查集 The Suspects POJ - 1611

原题:

   The Suspects

警察抓贩毒集团。有不同类型的犯罪集团,人员可能重复,集团内的人会相互接触。现在警察在其中一人(0号)身上搜出毒品,认为与这个人直接接触或通过其他人有间接接触的人都是嫌疑犯。问包括0号犯人共有多少嫌疑犯?

Input

多样例输入。
每个测试用例以两个整数n和m开头,其中n为人数,m为犯罪集团数。你可以假定0 < n <= 30000和0 <= m <= 500。在所有的情况下,每个人都有自己独特的整数编号0到n−1, 且0号是公认的嫌疑犯。
接下来m行输入,每个犯罪集团一行。每一行从一个整数k开始,它本身表示集团内成员的数量。按照成员的数量,在这个组中有k个整数表示人员。一行中的所有整数都被至少一个空格隔开。
n = 0且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

题意: 统计和0号嫌犯有关的所有人

题解:通过路径压缩,把和 0 号嫌犯有关的人放在一个集合

#include<cstdio>
using namespace std;
const int maxn = 30005;
int a[maxn],sum[maxn];
void init(int n){
	for(int i = 0;i < n;i++){  // 初始化 
		a[i] = i;
		sum[i] = 1;
	}
}
int get(int i){  			// 寻找父节点 并且路径压缩 
	if(a[i] != i){
		a[i] = get(a[i]);  // 这里需要体会,模拟过程 
	}
	return a[i];
}
void merge(int x,int y){
	int i = get(x);      // 找 X 父节点 
	int j = get(y);		// 找 Y 父节点 
	if(i != j){				//如果节点不同,合并为一个点 
		a[j] = i;
		sum[i] += sum[j];  // 求和 
	}
}
int main(){
	int n,m;
	while(scanf("%d%d",&n,&m) != EOF){
		if(n == 0 && m == 0){
			break;
		}
		init(n);
		while(m--){
			int x,y,z;
			scanf("%d",&x);
			scanf("%d",&y);
			for(int i = 1;i < x;i++){
				scanf("%d",&z);
				merge(y,z);    // 合并
			}
		}
		printf("%d\n",sum[get(0)]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/error311/article/details/81876770