1. 程式人生 > >貪心演算法(Greedy Algorithm)之最小生成樹 克魯斯卡爾演算法(Kruskal's algorithm)

貪心演算法(Greedy Algorithm)之最小生成樹 克魯斯卡爾演算法(Kruskal's algorithm)

克魯斯卡爾演算法(Kruskal's algorithm)是兩個經典的最小生成樹演算法的較為簡單理解的一個。這裡面充分體現了貪心演算法的精髓。大致的流程可以用一個圖來表示。這裡的圖的選擇借用了Wikipedia上的那個。非常清晰且直觀。

首先第一步,我們有一張圖,有若干點和邊

如下圖所示:

graph

第一步我們要做的事情就是將所有的邊的長度排序,用排序的結果作為我們選擇邊的依據。這裡再次體現了貪心演算法的思想。資源排序,對區域性最優的資源進行選擇。

排序完成後,我們率先選擇了邊AD。 這樣我們的圖就變成了

圖1

第二步,在剩下的變中尋找。我們找到了CE。這裡邊的權重也是5

圖二

依次類推我們找到了6,7,7。完成之後,圖變成了這個樣子。

圖三

下一步就是關鍵了。下面選擇那條邊呢? BC或者EF嗎?都不是,儘管現在長度為8的邊是最小的未選擇的邊。但是現在他們已經連通了(對於BC可以通過CE,EB來連線,類似的EF可以通過EB, BA, AD, DF來接連)。所以我們不需要選擇他們。類似的BD也已經連通了(這裡的連通線用紅色表示了)。所以最後就剩下EG和FG了。當然我們選擇了EG。 最後成功的圖就是下圖:

圖四

到這裡所有的邊點都已經連通了,一個最小生成樹構建完成。

如果要簡要得描述這個演算法的話就是,首先邊的權重排序。(從小到大)迴圈的判斷是否需要選擇這裡的邊。判斷的依據則是邊的兩個頂點是否已經連通,如果連通則繼續下一條。不連通就選擇使其連通。這個流程還是非常清晰明瞭。

但是在實現的時候,困難的地方在於如何描述2個點已然連通? 這裡用到了並查集做輔助,至於並查集可以到這裡去看看。

這裡貼出並查集的程式碼和Kruscal的C++實現: