51nod 1212 無向圖最小生成樹(Kruskal演算法)
阿新 • • 發佈:2019-01-01
收藏
關注
N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。
Input
Output示例
第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
輸出最小生成樹的所有邊的權值之和。Input示例
9 14 1 2 4 2 3 8 3 4 7 4 5 9 5 6 10 6 7 2 7 8 1 8 9 7 2 8 11 3 9 2 7 9 6 3 6 4 4 6 14 1 8 8
37
這是一道最小生成樹的模板的題,用的是Kruskal演算法,這沒什麼好說的,但是有一點我一定要說明一下
那就是最短路與最小生成樹的區別,反正本校的新生經常問我這個問題,我剛學的時候也經常搞混23333
最短路與最小生成樹的區別:
最短路是要求一點到另外的點的最短路徑,只要最短的長度到達就好,除了出發點和終點外一概不管。如果不求一點到所有點的最短路,甚至可以不管所有點是否都聯通。 最小生成樹則要保證第一所有點都是聯通的,不然就稱不上是樹了,而後保證樹的邊長度之和最小。
最後我們就上程式碼吧~:
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<algorithm> using namespace std; #define MAX 50005 int father[MAX], son[MAX]; int v, l; typedef struct Kruskal //儲存邊的資訊 { int a; int b; int value; }; bool cmp(const Kruskal & a, const Kruskal & b) { return a.value < b.value; } int unionsearch(int x) //查詢根結點+路徑壓縮 { return x == father[x] ? x : unionsearch(father[x]); } bool join(int x, int y) //合併 { int root1, root2; root1 = unionsearch(x); root2 = unionsearch(y); if(root1 == root2) //為環 return false; else if(son[root1] >= son[root2]) { father[root2] = root1; son[root1] += son[root2]; } else { father[root1] = root2; son[root2] += son[root1]; } return true; } int main() { int ncase, ltotal, sum, flag; Kruskal edge[MAX]; scanf("%d%d", &v, &l); ltotal = 0, sum = 0, flag = 0; for(int i = 1; i <= v; ++i) //初始化 { father[i] = i; son[i] = 1; } for(int i = 1; i <= l ; ++i) { scanf("%d%d%d", &edge[i].a, &edge[i].b, &edge[i].value); } sort(edge + 1, edge + 1 + l, cmp); //按權值由小到大排序 for(int i = 1; i <= l; ++i) { if(join(edge[i].a, edge[i].b)) { ltotal++; //邊數加1 sum += edge[i].value; //記錄權值之和 //cout<<edge[i].a<<"->"<<edge[i].b<<endl; } if(ltotal == v - 1) //最小生成樹條件:邊數=頂點數-1 { flag = 1; break; } } if(flag) printf("%d\n", sum); else printf("data error.\n"); return 0; }