無向圖最小產生樹
N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小產生樹。
Input 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000)
第2 - M + 1行:每行3個數S E W,分別表示M條邊的2個頂點及權值。(1 <= S, E <= N,1 <= W <= 10000) Output 輸出最小產生樹的所有邊的權值之和。 Sample Input
9 141 2 42 3 83 4 74 5 95 6 106 7 27 8 18 9 72 8 113 9 27 9 63 6 44 6 141 8 8
Sample Output
37
解題思路:
其實就是一道最小產生樹的模板題,用Kruskal演算法來寫。將每條路的資訊儲存起來,並將邊的權值按從小到大進行排序,每次選擇權值最小的邊加入樹中,並把邊的兩個頂點加入到一個集合中,若這兩個頂點本身就在一個集合中(即加入這條邊就構成了迴路),就捨棄這條邊判斷下一個。直到選取了n-1條邊加入樹中,最小產生樹構造完成。具體看代碼。
代碼如下:
#include<stdio.h>#include<string.h>#include<algorithm>#define INF 0x3f3f3f3f //定義極大值INFusing namespace std;int n, m, sum, ans;int f[1010]; //數組f判斷點的集合狀態struct node{ int x; int y; //儲存邊的兩個頂點以及權值 int z;} Q[50010];bool cmp( node a, node b ){ return a.z < b.z; //將權值從小到大排列}int getf( int v ){ if( v != f[v] ) f[v] = getf(f[v]); //尋找父節點 return f[v];}int lian( int t1, int t2 ){ int v1 = getf(t1); int v2 = getf(t2); if( v1 != v2 ) { //若兩個頂點不在同一集合中,這條邊加入樹 f[v1] = v2; return 1; } return 0;}void Kruskal(){ for( int i = 0; i < m; i++ ) { if( lian(Q[i].x,Q[i].y) ) { ans++; sum = sum + Q[i].z; if( ans == n-1 ) //當選取n-1條邊時最小產生樹構造完成 break; } }}int main(){ while( ~scanf("%d%d",&n,&m) ) { for( int i = 0; i < m; i++ ) scanf("%d%d%d",&Q[i].x,&Q[i].y,&Q[i].z); sort(Q,Q+m,cmp); sum = ans = 0; for( int i = 1; i <= n; i++ ) f[i] = i; //初始化父節點都是本身 Kruskal(); printf("%d\n",sum); } return 0;}