Description:
世界上有许多宗教,你感兴趣的是你学校里的同学信仰多少种宗教。
你的学校有n名学生(0 < n <= 50000),你不太可能询问每个人的宗教信仰,因为他们不太愿意透露。但是当你同时找到2名学生,他们却愿意告诉你他们是否信仰同一宗教,你可以通过很多这样的询问估算学校里的宗教数目的上限。你可以认为每名学生只会信仰最多一种宗教。
Input:
输入包括多组数据。每组数据的第一行包括n和m,0 <= m <= n(n-1)/2
其后m行每行包括两个数字i和j,表示学生i和学生j信仰同一宗教,学生被标号为1至n。输入以一行 n = m = 0 作为结束。
Output:
对于每组数据,先输出它的编号(从1开始),接着输出学生信仰的不同宗教的数目上限。
Sample Input:
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
Sample Output:
Case 1: 1 Case 2: 7
思路:
用并查集解决,未连边时的最大信仰数为n,每联结一次,最大信仰数减1。连结点的时候注意要用一个连通分量的根连到另一个的根,因为本身关联关系应该是个无向图而用并查集的时候人为规定了方向,点连点或是点连根会导致指向混乱,根连根避免方向问题,因为根没有指向(只能被指)
例子:
5 3
2 4
1 5
2 5
Case 1: 2
代码:
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,ans,T=0;
int student[50010]; //学生i的信仰与student[i]的信仰相同
int find(int x) //查询祖先
{
if(student[x]==x)return x;
else return student[x]=find(student[x]);
}
void unite(int x,int y) //联接两个信仰不同的学生
{
if(find(x)==find(y))return;
else {
student[find(y)]=find(x);
ans--;
}
}
int main()
{
while(cin>>n>>m)
{
T++;
if(n==0&&m==0)break;
ans=n;
for(int i=1;i<=n;i++)
student[i]=i;
int a,b;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&a,&b);
unite(a,b);
}
printf("Case %d: %d\n",T,ans);
}
}
原题链接:
http://noi.openjudge.cn/ch0403/1526