1. 程式人生 > >模板--最小生成樹 Kruskal 演算法不詳解

模板--最小生成樹 Kruskal 演算法不詳解

最小生成樹

  是由n個節點的連通圖變化來的。這棵樹滿足如下條件:

    1、是原來圖的子圖(原來的圖扣去了幾條邊)

    2、在保證圖仍然連通的情況下,剩下的邊權和是最小的

    3、滿足樹的性質

  最小生成樹常用來解決這樣的問題:

    有n個村莊,他們之間本沒有路(走的人多了就有路了)。我們現在知道每兩個村莊之間修路的費用,求最少的修路費用。要求修路後任意兩個村莊均可到達。

Kruskal 演算法

  很容易想到,1、我們希望取的邊權(路費)要儘量小(貪心)。

        2、如果a和b之間修了一條路,b和c之間修了一條路,那麼我們就不必再在a和c之間修路了(所以滿足樹的性質)。

  所以,我們從權值最小的邊開始列舉(sort),將它連通的點標記為連通(放到同一個並查集中)。如果有兩點已經連通(a->b->c 即視為a與c連通),跳過這條邊,繼續向後列舉。

  如果不連線較短邊而通過更長的邊連線,一定不會比連線更短邊更優。。。

  關於並查集的知識,請。。。百度

  貪心演算法請感性理解。。。(逃ε=ε=ε=┏(゜ロ゜;)┛)

  不扯了,上程式碼:

 1 //自我感覺碼風良好(滑稽)
 2 //應該比較易懂,變數名大都與含義對應,
 3 //本程式碼耗時比較多    
 4 //PS:AC是肯定能AC的(luogu P3366)
 5 //多說一句,這個題所有的點都連通。。。
6 7 8 #include <cstdio> 9 #include <algorithm> 10 11 using namespace std; 12 13 const int MAXN = 5005; 14 const int MAXM = 400005; 15 16 struct Edge { 17 int from, to, val; 18 }edge[MAXM]; 19 20 int num_edge, n, m, ans; 21 int x, y, z; 22 int f[MAXN]; 23 24 inline void AddEdge(int
from, int to, int val); 25 inline int getfather(int x); 26 inline void merge_set(int x, int y); 27 bool comp(const Edge a, const Edge b); 28 29 30 int main() { 31 scanf("%d%d", &n, &m); 32 for(int i = 1; i <= n; i++) f[i] = i; 33 for(int i = 0; i < m; i++) { 34 scanf("%d%d%d", &x, &y, &z); //無向圖 從x到y有一條長度為z的邊 35 AddEdge(x, y, z); //無向圖 36 AddEdge(y, x, z); //無向圖 37 } 38 39 sort(edge, edge + num_edge, comp); //這很Kruskal QwQ 40 41 for(int i = 0; i < num_edge; i++) { 42 int from = edge[i].from; 43 int to = edge[i].to; 44 int val = edge[i].val; 45 if(getfather(from) == getfather(to)) continue; //這兩點已經在同一個並查集中 46 merge_set(from, to); 47 ans += val; 48 } 49 printf("%d", ans); 50 return 0; 51 } 52 53 54 inline void AddEdge(int from, int to, int val) { //顧名思義 55 edge[num_edge].from = from; 56 edge[num_edge].to = to; 57 edge[num_edge].val = val; 58 num_edge++; 59 } 60 61 62 inline int getfather(int x) { //顧名思義 63 if(f[x] == x) return x; //路徑壓縮 64 f[x] = getfather(f[x]); 65 return f[x]; 66 } 67 68 inline void merge_set(int x, int y) { //合併兩個並查集 69 int fx = getfather(x); //沒有打按秩合併QwQ 70 int fy = getfather(y); 71 f[fx] = f[fy]; 72 } 73 74 bool comp(const Edge a, const Edge b) { 75 return (a.val < b.val); 76 }