說說最小生成樹(Minimum Spanning Tree)


minimum spanning tree(MST)

最小生成樹是連通無向帶權圖的一個子圖,要求

能夠連接圖中的所有頂點、無環、路徑的權重和為所有路徑中最小的.

graph-cut

對圖的一個切割或者叫切斷,會使圖分離成為兩個不相連的頂點集.
它基於樹的兩個基本屬性:

為樹的任意兩個節點間添加一條邊,會在樹中形成一個環.
刪去樹中的一條邊,會將原樹分離成兩棵不相連的樹.

crossing edge

有了切斷的概念,很容易就會問到,被切開的那些邊是什么?

切斷造成了兩個不相連的頂點集,而切斷的操作施加在這些邊上,那么這些邊本身就橫跨了兩個頂點集.

prim’s algorithm

最常用的一種求MST的算法是普利姆算法

它是一種貪心算法.
它搜索的方向是從某一個頂點開始,對所有鄰接的邊進行考察,然后將最輕的邊(權重最小的邊)加入MST.
決定它下一步搜索方向的,是最輕邊的另一端的頂點,從這個頂點開始,它重復上一步,直到所有的頂點訪問完畢.

由於普利姆算法每次都貪心地找當前看來最輕的邊,它不會綜合考量全局,所以它是一種貪心算法.
由於它從最輕邊的另一個端點繼續它的搜索之旅,所以每一步求出的在MST中的邊都會自然地連成一顆樹,直到最后長大為MST.

PriorityQueue

在普利姆算法中,一個重要的操作是挑選最輕邊,所以一個優先隊列可以對這個操作進行優化支持.

優先隊列通常基於堆來實現,比如二叉堆.它可以給我們對數級的時間返回隊頭元素,而這個隊頭元素具有最高的優先級.
如果我們規定越輕的邊的優先級越高,那么一個小根堆實現的升序優先隊列就可以用在普利姆算法中.

prim

lazy prim

普利姆算法在找到一條最輕邊(v,w)后,這條邊就不應該在以后的搜索中成為一個備選,同時點w也被加入了MST,那么優先隊列中所有還未訪問的但和點w連着的那些邊都成了廢棄邊,它們不應該被再次考察.

那么如何處理這種不再備選的邊?
我們可以刪除這些邊,但是刪除這條邊后,邊的另一端頂點還沒有訪問,我們的刪除操作會波及那些還沒有訪問的頂點.
那么,一個比較懶而直觀的方式是

推遲對所有的廢棄邊的刪除操作,任由它們在優先隊列中,作為隊列一員參與隊列的每次調整操作.

采取懶惰方式的普利姆算法的時間復雜度是O(ElogE).從這里看出,它對邊比較稠密的圖來說,是低效的.
如果要了解懶惰方式的的普利姆算法,請參考:普利姆算法lazy實現

eager prim

以懶惰方式處理不再備選的邊,會使得算法多次考察這樣的邊,影響了效率.

有沒有方法對它進行改進?
考慮一下,我們在找出一條最輕邊並將它加入MST后,實際上使得其它的還沒有被訪問的邊被訪問的機會增加了.

而我們只對最輕邊感興趣,所以在考察一個頂點時,只需要在優先隊列中維護一條目前已知的到這個頂點的最短距離或最小權重就可以了.

為了不將廢棄邊加入隊列,我們需要以索引方式來組織優先隊列.

關於索引式的優先隊列,請參考:索引式 優先隊列

以積極方式隊列廢棄邊的算法,請參考:普利姆算法eager實現

普利姆算法的eager實現的時間復雜度是最差O(ElogV )

kruskal’s algorithm

克魯斯卡爾算法是求MST的另一種常用算法,它非常簡單:

1.每一步都挑選當前看來最輕的邊.如果這條邊的兩個端點的加入,沒有在mst中造成回路,將這條邊加入mst.
2.對所有的邊重復上一步.

算法中比較關鍵的一個操作是判斷是否形成回路(cycle),這可以借助並查集來做,請參考:快速並查集

克魯斯卡爾算法的時間復雜度為O(ElogE).
這里是一個完成的算法實現,請參考:克魯斯卡爾算法實現

綜述

最小生成樹和最小生成森林(minimum spanning forest)技術,對於連通性考察很有意義.

克魯斯卡爾算法和懶惰方式的普利姆算法形式簡單、易於理解,適合處理邊不稠密的圖.

積極方式的普利姆算法,初次接觸會不易理解.但它效率高於懶惰方式,平均適用性更好.

求MST的貪心算法,都離不開優先隊列或堆的支持,堆的操作效率決定了這些算法的效率.
如果用斐波那契堆來實現優先隊列,則decrease-key操作的攤還代價是O(1 ),普里姆算法將可優化到:O(E+VlogV ).


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM