1. 程式人生 > >HDU 1232 暢通工程 並查集簡單應用

HDU 1232 暢通工程 並查集簡單應用

暢通工程

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


解題思路:

考慮的案例1

這裡給出四個頂點,兩條邊,連通了1-3-4,於是整個圖被分為1-3-4 , 2兩個部分,此時只要把增加一條邊把結點2連入任意一個頂點,圖就是連通的了。不難得到,連通n個部分需要新增的邊數就是n-1。

而並查集就是維護不相交集合的資料結構,這裡使用並查集對連通的結點進行合併。

#include<iostream>
#include<cstring>
using namespace std;
int f[1005];
int rank[1005]; 
void initSet(int n){
	memset(rank,0,sizeof(rank));
	for(int i=1;i<=n;i++){
		f[i]=i;
	}
}
int find(int x){
	if(f[x]==x)
		return x;
	else
		//壓縮路徑 回溯時儲存其根結點 
		return f[x]=find(f[x]);
}
void unionSet(int a,int b){
	int x=find(a);
	int y=find(b);
	if(x==y)
		return ;
	else{
		//比較樹的高度 低的往高的合併 
		if(rank[x]<=rank[y]){
			f[x]=y;	
			if(rank[x]==rank[y]){
				rank[x]++;	
			}
		}
		else{
			f[y]=x;
		} 
	}
}
int main(){
	int n,m,res;
	while(~scanf("%d",&n)&&n){
		initSet(n);
		cin>>m;
		int a,b;
		for(int i=0;i<m;i++){
			cin>>a>>b;
			unionSet(a,b);
		}
		res=0;
		for(int i=1;i<=n;i++){
			if(f[i]==i)
				sum++;
		}
         printf("%d\n",res);
	}
	return 0;
}