世界上有许多宗教,你感兴趣的是你学校里的同学信仰多少种宗教。你的学校有 n 名学生(0 < n ≤50000),你不太可能询问每个人的宗教信仰,因为他们不太愿意透露。但是当你同时找到 2 名学生,他们却愿意告诉你他们是否信仰同一宗教,你可以通过很多这样的询问估算学校里的宗教数目的上限。你可以认为每名学生只会信仰最多一种宗教。
输入格式
输入包括多组数据。每组数据的第一行包括 n 和 m,0 <= m ≤n(n−1)/2,其后 mm行每行包括两个数字 i 和 j,表示学生 i 和学生 j 信仰同一宗教,学生被标号为 1 至 n。
输入以一行 n = m = 0作为结束。
输出格式
对于每组数据,先输出它的编号(从 1开始),接着输出学生信仰的不同宗教的数目上限。
输出时每行末尾的多余空格,不影响答案正确性
样例输入:
10 9
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
10 4
2 3
4 5
4 8
5 8
0 0
样例输出:
Case 1: 1
Case 2: 7
思路:可以类比着acwing并查集模板题中连通块中点的数量
代码:
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 50010;
int fa[N], cnt[N];
int n, m;
int find(int x) {
if (fa[x] != x)
fa[x] = find(fa[x]);
return fa[x];
}//路径压缩
int main() {
int ss = 0;
while (cin >> n >> m) {
if (n == 0 && m == 0)
return 0;
for (int i = 1; i <= n; i++) {
cnt[i] = 1;//刚开始时每个集合中只有一个数据,即它们自己
fa[i] = i;
}
while (m--) {
int x, y;
cin >> x >> y;
int a = find(x);
if (find(x) != find(y)) {
fa[find(x)] = find(y);//让y的父节点成为x的祖宗节点
cnt[find(y)] += cnt[a];//将x加到y所在的集合中
cnt[a] = 0;//将x所在集合清零
}
}
ss++;
int hh = 0;
for (int i = 1; i <= n; i++) {
if (cnt[i] > 0)//考虑到可能会有一个人和别人信仰的宗教都不一样,此时它的集合中只有它自己
hh++;
}
printf("Case %d: ", ss);
cout << hh << endl;
}
return 0;
}
如果出现问题,欢迎批评指正哈