1. 程式人生 > >NOI 4.3 圖論 1526:宗教信仰

NOI 4.3 圖論 1526:宗教信仰

1526:宗教信仰

總時間限制5000ms    記憶體限制65536kB

描述

世界上有許多宗教,你感興趣的是你學校裡的同學信仰多少種宗教。

你的學校有n名學生(0 < n <= 50000),你不太可能詢問每個人的宗教信仰,因為他們不太願意透露。但是當你同時找到2名學生,他們卻願意告訴你他們是否信仰同一宗教,你可以通過很多這樣的詢問估算學校裡的宗教數目的上限。你可以認為每名學生只會信仰最多一種宗教。

輸入

輸入包括多組資料。每組資料的第一行包括nm0 <= m <= n(n-1)/2,其後m行每行包括兩個數字ij,表示學生i和學生j信仰同一宗教,學生被標號為1n。輸入以一行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

-----------------------------------------------------

思路

題意:已知圖中節點的連線關係,求圖中的連通支數量。

並查集模板題。關於並查集的詳細介紹,可以看這篇神奇的博文一個很有意思的並查集詳解

-----------------------------------------------------

程式碼

// 並查集

#include<iostream>
#include<fstream>
using namespace std;

const int NMAX = 50005;
int pre[NMAX] = {};								// 每個節點的父節點
int n = -1;										// 全域性變數:學生人數
int cnt = n;									// 全域性變數:總的集合個數

int find(int x)									// 輸入一個節點的編號,返回該節點在並查集中的根節點
{
	int r = pre[x],t = x;
	while (r!=t)								// 如果不是根節點(父節點==自己),則不斷上溯
	{
		t = r;
		r = pre[t];
	}
	// 路徑壓縮過程
	t = x;
	int tt = x;
	while (t!=r)								// 從葉子節點開始回溯,把路徑上的所有節點的父節點全都設為根節點
	{
		tt = pre[t];
		pre[t] = r;
		t = tt;
	}

	return r;
}

void join(int x, int y)							// 合併兩個元素所在集合
{
	int xx = find(x), yy = find(y);				// 分別找到兩個元素的根節點
	if ( xx!= yy)								// 如果兩個元素的根節點不同, 則需要合併; 否則兩個元素本來就在同一個集合
	{
		cnt--;									// 總的集合個數-1
		pre[xx] = yy;							// 將一個集合的根節點的父節點設為另一個集合的根節點
	}
}



int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin ("0403_1526.txt");
	int m,i,x,y,t=0;
	while (fin >> n >> m)
	{
		if (n==0 && m==0)
		{
			break;
		}
		for (i=0; i<n; i++)
		{
			pre[i] = i;
		}
		cnt = n;
		for (i=0; i<m; i++)
		{
			fin >> x >> y;
			join(x,y);
		}
		cout << "Case "<< (++t) << ": " << cnt << endl;
	}
	fin.close();
#endif
#ifdef ONLINE_JUDGE
	int m,i,x,y,t=0;
	while (cin >> n >> m)
	{
		if (n==0 && m==0)
		{
			break;
		}
		for (i=0; i<n; i++)
		{
			pre[i] = i;
		}
		cnt = n;
		for (i=0; i<m; i++)
		{
			cin >> x >> y;
			join(x,y);
		}
		cout << "Case "<< (++t) << ": " << cnt << endl;
	}
#endif
}