题目大意
有n(n<=10000)个罪犯以及m(m<100000)组罪犯间的关系,每个犯罪团伙中的罪犯间都相互或间接相互认识,现求这些罪犯中共存在多少个犯罪团伙。当然,也有可能一个犯罪团伙只有一个人。
输入输出
输入有若干行
第一行为罪犯数量n
第二行为关系数量m
接下来的m行每行有两个用空格隔开的数,表示某两个罪犯相互认识
输出有一行,表示犯罪团伙的数量
样例输入:
11
8
1 2
4 5
3 4
1 3
5 6
7 10
5 10
8 9
样例输出:
3
算法讨论
这题可以使用并查集解决。我们可以建立一个数组father[10000]来表示罪犯i与罪犯father[i]在一个团伙中。然后,每当我们输入一组罪犯关系”a b”时,将将a赋值给father[b]。这样操作直到输入完成后,我们就得到了一棵棵代表犯罪团伙的树。
接着定义一个初始值为0的变量gang,用它来统计犯罪团伙总数。然后从1到n遍历father。如果father[i]==i,就说明这是一个犯罪团伙的根结点,那么就gang++,最后将gang输出即可。
代码实现
#include <iostream>
#include <cstdio>
using namespace std;
int father[100000] = {0};
int find(int x){ //查找祖先结点
if (father[x] != x) father[x] = find(father[x]);
return father[x];
}
void Merge(int a, int b){ //合并两个集合
father[find(b)] = find(a);
}
int main(){
int m, n, counting = 0;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
father[i] = i; //初始化犯罪团伙
for (int i = 0; i < m; i++) {
int a, b;
scanf("%d %d", &a, &b);
Merge(a, b); //合并犯罪团伙
}
for (int i = 1; i <= n; i++)
if (father[i] == i) counting++; //计算数量
printf("%d\n", counting);
return 0;
}