Kruskal算法的高效實現需要一種稱作並查集的結構。我們在這里不介紹並查集,只介紹Kruskal算法的基本思想和證明,實現留在以后討論。
Kruskal算法的過程:
(1) 將全部邊按照權值由小到大排序。
(2) 按順序(邊權由小到大的順序)考慮每條邊,只要這條邊和我們已經選擇的邊不構成圈,就保留這條邊,否則放棄這條邊。
算法 成功選擇(n-1)條邊后,形成一棵最小生成樹,當然如果算法無法選擇出(n-1)條邊,則說明原圖不連通。
(2) 按順序(邊權由小到大的順序)考慮每條邊,只要這條邊和我們已經選擇的邊不構成圈,就保留這條邊,否則放棄這條邊。
算法 成功選擇(n-1)條邊后,形成一棵最小生成樹,當然如果算法無法選擇出(n-1)條邊,則說明原圖不連通。
以下圖為例:

邊排序后為:
1 AF 1
2 DE 4
3 BD 5
4 BC 6
5 CD 10
6 BF 11
7 DF 14
8 AE 16
9 AB 17
10 EF 33
算法處理過程如下:

處理邊AF,點A與點F不在同一個集合里,選中AF。

處理邊DE,點D與點E不在同一個集合里,選中DE

處理邊BD,點B與點D不在同一個集合里,選中BD

處理邊BC,點B與點C不在同一個集合里,選中BC

處理邊CD,點C與點D在同一個集合里,放棄CD。
處理邊BF,點B與點F不在同一個集合里,選中BF。
至此,所有的點都連在了一起,剩下的邊DF,AE,AB,EF不用繼續處理了,算法執行結束。
Kruskal算法的證明。假設圖連通,我們證明Krusal算法得到一棵最小生成樹。我們假設Kruskal算法得到的樹是K (注意我們已經假設Kruskal算法一定可以得到生成樹)。假設T是一棵最小生成樹,並且K ≠T, K中顯然至少有一條邊。我們找到在K中,而不在T中最小權值的邊e。
把e加入T中,則形成一個圈,刪掉這個圈中不在K中的邊f,得到新的生成樹T’。
f的存在性,如果全里面所有的邊都在K中,則K包含圈,矛盾。
考慮邊權值關系:
(1) 若w(f) > w(e), 則T’的權值和小於T的權值和,與T是最小生成樹矛盾。
(2) 若w(f) < w(e), 說明Kruskal算法在考慮加入e之前先考慮了邊f,之所以沒加入f是因為f和之前加入的邊形成圈,之前加入的邊權值顯然不超過w(f) (因為加邊是從小到大的順序加入的),所以之前加入的邊權值一定小於w(e)。而根據e的定義,K中權值小於w(e)的邊都在T中,這說明T中的邊會和f構成圈,矛盾。
所以只能w(f) = w(e)。T’仍然是最小生成樹,而T’和K相同的邊多了一條。
這樣下去有限步之后,最終可以把T變為K,從而K也是最小生成樹。
把e加入T中,則形成一個圈,刪掉這個圈中不在K中的邊f,得到新的生成樹T’。
f的存在性,如果全里面所有的邊都在K中,則K包含圈,矛盾。
考慮邊權值關系:
(1) 若w(f) > w(e), 則T’的權值和小於T的權值和,與T是最小生成樹矛盾。
(2) 若w(f) < w(e), 說明Kruskal算法在考慮加入e之前先考慮了邊f,之所以沒加入f是因為f和之前加入的邊形成圈,之前加入的邊權值顯然不超過w(f) (因為加邊是從小到大的順序加入的),所以之前加入的邊權值一定小於w(e)。而根據e的定義,K中權值小於w(e)的邊都在T中,這說明T中的邊會和f構成圈,矛盾。
所以只能w(f) = w(e)。T’仍然是最小生成樹,而T’和K相同的邊多了一條。
這樣下去有限步之后,最終可以把T變為K,從而K也是最小生成樹。
N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。
最后,我們來提供輸入輸出數據,由你來寫一段程序,實現這個算法,只有寫出了正確的程序,才能繼續后面的課程。
輸出示例
輸入
第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)
輸出
輸出最小生成樹的所有邊的權值之和。
輸入示例
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