1. 程式人生 > >NOI題庫-1526 宗教信仰

NOI題庫-1526 宗教信仰

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