1. 程式人生 > >【並查集】通暢工程(航電1232)

【並查集】通暢工程(航電1232)

通過 統計 iostream clu 連接 tail efi pac des

轉自:http://blog.csdn.net/dellaserss/article/details/7724401/(並查集的講解非常有趣)


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

Source

浙大計算機研究生復試上機考試-2005年

分析:

因為並查集可以高效的進行查詢元素a和元素b是否屬於同一個組及合並元素a和元素b所在的組,所以看出此題考察並查集。因為問最少還需要建設多少條路,N個點將其連成一條線就是最少的情況,即最少需要ans=N-1條路,才能將N個鎮連通起來。又給出了已經修建的路連接的結點,先假設沒有一條路,然後判斷兩個給出的結點,如果兩個結點不是一個根結點,那麽合並結點,需要建的路就少一條,ans--,如果下次還是這兩個結點,ans不會減減。

參考代碼:

#include <iostream>
#include <stdio.h>
#define MAX_N 100
using namespace std;
/*
並查集:
1)par[n]整形數組
2)int find(int x)查找函數
3)void unite(int x,int y)合並函數
*/
//該數組存的是該結點的前導點
int par[MAX_N];
int find(int x);
void unite(int x,int y);
void init(int n);

int main()
{
    int N,M;
    int x,y;
    
int ans; while(scanf("%d",&N)&&N){ init(N); //因為問最少需要建設多少道路,所以N個點最少需要N-1條 ans=N-1; scanf("%d",&M); for(int i=1;i<=M;i++){ scanf("%d%d",&x,&y); if(find(x)!=find(y)){ unite(x,y); ans--; } } printf("%d\n",ans); } return 0; } //查找x的根結點,並進行路徑壓縮 int find(int x){ int r,i,j; i=x; while(par[i]!=i){ i=par[i]; } r=i; //查詢結點的同時壓縮路徑,讓所有的結點的前導點都是根結點 while(x!=r){ j=par[x]; par[x]=r; x=j; } return r; } //合並不是一個根結點的兩個結點 void unite(int x,int y){ int rx=find(x); int ry=find(y); if(rx!=ry){ par[y]=rx; } } //初始化,每個結點的前導點都是自己 void init(int n){ //因為城鎮編號是1~N,所以從1開始 for(int i=1;i<=n;i++){ par[i]=i; } }

【並查集】通暢工程(航電1232)