1. 程式人生 > >最小生成樹問題(並查集解決)

最小生成樹問題(並查集解決)

pan font 距離 輸入 nbsp flag -o return quest

傳統的Prim算法或者是Kruskal算法求最小生成樹時,要先把圖創建出來,就比較麻煩。

如果用並查集來解決,依次選取權值最小的邊,判斷它們是否在一個並查集內,如果在則舍去,如果不在則加入,簡單了很多。

題目描述

某省調查鄉村交通狀況,得到的統計表中列出了任意兩村莊間的距離。省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可達即可),並要求鋪設的公路總長度為最小。請計算最小的公路總長度。

輸入描述:

    測試輸入包含若幹測試用例。每個測試用例的第1行給出村莊數目N ( < 100 );隨後的N(N-1)/2行對應村莊間的距離,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間的距離。為簡單起見,村莊從1到N編號。
    當N為0時,輸入結束,該用例不被處理。

輸出描述:

    對每個測試用例,在1行裏輸出最小的公路總長度。
示例1

輸入

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

輸出

3
5

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 
 5 int Find( int x);
 6 int Union(int x, int y);
 7 int cmp( const void *a, const void *b);
 8 
 9
typedef struct Edge 10 { 11 int a,b; 12 int cost; 13 } Edge; 14 Edge edge[6002]; 15 int bcj[102]; 16 17 int main() 18 { 19 int n,m; 20 int i; 21 int ans,flag; 22 while( scanf("%d",&n)!=EOF) 23 { 24 if( n==0) break; 25 m = n*(n-1)/2; 26 memset( bcj,-1
,102*sizeof(int)); //並查集初始化 27 ans =0; 28 for( i=0; i<m; i++) 29 { 30 scanf("%d %d %d",&edge[i].a,&edge[i].b,&edge[i].cost); 31 32 } 33 qsort( edge,m,sizeof(edge[0]),cmp); //依據權值進行快速升序排序 34 35 for( i=0; i<m; i++) 36 { 37 flag = Union( edge[i].a,edge[i].b); //判斷一條邊的兩個端點是否在一個並查集內 38 if( flag==1 ) ans += edge[i].cost; //如果不在一個並查集內則加該邊權值 39 } 40 printf("%d\n",ans); 41 } 42 return 0; 43 } 44 45 int Find( int x) 46 { 47 if( bcj[x]<0 ) return x; 48 return bcj[x] = Find( bcj[x]); 49 } 50 51 int Union(int x, int y) 52 { 53 x = Find( x ); 54 y = Find( y ); 55 56 if( x==y ) return 0; 57 58 bcj[x] += bcj[y]; 59 bcj[y] = x; 60 return 1; 61 62 } 63 64 int cmp( const void *a, const void *b) 65 { 66 Edge *c = (Edge *)a; 67 Edge *d = (Edge *)b; 68 return c->cost - d->cost; 69 }

最小生成樹問題(並查集解決)