POJ2425 Ubiquitous Religions(并查集板题)
题目链接:POJ2425 Ubiquitous Religions
题目翻译:
一个大学中有n(编号由1~n)个学生,我们无法确定他们分别信仰什么宗教,但我们可以确定有m对同学信仰相同的宗教
现给出这m对同学的编号,请问他们最多信仰多少种不同的宗教?
输入格式:
现在有若干对的数据,输入n,m,当n == 0且m == 0时结束输入
每一对数据分为m+1行,第1行输入n,m,第2~m+1行输入这m对同学的关系
输出格式:
假设现在输入的是第tot对数据,输出“Case tot: ans\n”(不带引号)
样例解释:(见题面,请自行手模)
问题分析:
就是最开始是有n个连通块,每次判断一下
- 如果他们已经在同一连通块内,那么没有必要再把他们加到连通块内
- 否则,连通块的个数要减一,并且将他们加到同一连通块内
最后放出代码:
#include <cstdio>
#include <iostream>
using namespace std;
int read() {
int w = 1,res = 0;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') res = res * 10 + ch - '0', ch = getchar();
return w * res;
}
int pre[50010]; //并查集父亲数组
int find(int k) {
return k == pre[k] ? k : pre[k] = find(pre[k]); //路径压缩加上求祖先
}
int main() {
int n, m, tot = 0;
while(cin >> n >> m) {
if(n == 0 && m == 0) return 0;
int ans = n; //最开始有n个连通块
for(int i = 1; i <= n; i ++) pre[i] = i; //把自己定义成自己的父亲
while(m --) {
int a = read(), b = read(); //a,b信仰同一宗教
if(find(a) != find(b)) { //如果他们不在同一连通块内
ans --; //那么总连通块数--
pre[find(a)] = find(b); //将其加入到同一连通块内
}
}
printf("Case %d: %d\n", ++ tot, ans); //按格式输出
}
}