HDU1232 暢通工程【並查集】

問題鏈接:HDU1232 暢通工程

Problem Description

某省調查城鎮交通狀況,得到現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府“暢通工程”的目標是使全省任何兩個城鎮間都可以實現交通(但不一定有直接的道路相連,只要互相間接通過道路可達即可)。問最少還需要建設多少條道路?

 

 

Input

測試輸入包含若干測試用例。每個測試用例的第1行給出兩個正整數,分別是城鎮數目N ( < 1000 )和道路數目M;隨後的M行對應M條道路,每行給出一對正整數,分別是該條道路直接連通的兩個城鎮的編號。爲簡單起見,城鎮從1到N編號。
注意:兩個城市之間可以有多條道路相通,也就是說
3 3
1 2
1 2
2 1
這種輸入也是合法的
當N爲0時,輸入結束,該用例不被處理。

 

 

Output

對每個測試用例,在1行裏輸出最少還需要建設的道路數目。

 

 

Sample Input


 

4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0

 

 

Sample Output


 
1 0 2 998

Hint

Hint Huge input, scanf is recommended.

 

 

問題分析:這是一個有關圖的連通性問題,可以用並查集來解決。並查集中,連通的各個結點都會指向相同的根。

構建一個並查集,使得相互連通的子圖指向相同的根,發現到兩個互不相連的子圖時,增加一條邊使之相連。

 

以下兩種方法均正確,第二種更爲簡潔

#include <iostream>
#include <cstring>
using namespace std;
//////////////ac 並查集 
int p[1005];
int find(int x)
{
	if(p[x]==x)
	{
		return x;
	}
	else{
		int y=find(p[x]);
		p[x]=y;
		return y;
	}
}

int main()
{
	int n,m;
	int a,b;
	memset(p,0,sizeof(p));
	while(cin>>n>>m&&n!=0)
	{
		for(int i=1;i<=n;i++)
		{
			p[i]=i;
		}
		//輸入邊構造並查集 
		for(int i=0;i<m;i++)
		{
			cin>>a>>b;
			int x=find(a);
			int y=find(b);
			if(x!=y)
			{
				p[x]=y;
			}
		}
		// 逐個結點檢查是否聯通,如果不聯通則修一條道路使其聯通
		int s=0;
		int t=find(1);
		for(int i=2;i<=n;i++)
		{
			if(find(i)!=t)
			{
				int x=find(find(i));
				int y=find(t);
				if(x!=y)
				{
					p[x]=y;
				}
				s++;
			}
		}
		cout<<s<<endl;
	}
	return 0;
}

 

#include <iostream>
#include <cstring>
using namespace std;
//////////////ac 並查集 
int p[1005];
int find(int x)
{
	if(p[x]==x)
	{
		return x;
	}
	else{
		int y=find(p[x]);
		p[x]=y;
		return y;
	}
}

int main()
{
	int n,m;
	int a,b;
	int cnt; 
	memset(p,0,sizeof(p));
	while(cin>>n>>m&&n!=0)
	{
		for(int i=1;i<=n;i++)
		{
			p[i]=i;
			cnt=n-1;//使所有節點連通需要的邊的數目 
		}
		//輸入邊構造並查集 
		for(int i=0;i<m;i++)
		{
			cin>>a>>b;
			int x=find(a);
			int y=find(b);
			if(x!=y)
			{
				p[x]=y;
				cnt--;//每往並查集里加一個節點,所需邊的個數減1 
			}
		}

		cout<<cnt<<endl;
	}
	return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章