最小生成樹尋路(prim)

接着上一次的kruskal算法,此次講更高級的prim算法算法

#Prim Algorithm prim算法和經典的Dijkstra最短路徑尋路算法驚人的類似,都是採用層層擴散的方式收斂出樹。同時又與kruskal算法分享着相似的邏輯。關於Dijkstra算法敬請參考以前發佈的《SPF算法完美教程》,若是沒聽過它也無礙,prim算法將展現它的思想。 前提準備:總共n個節點編號,放入集合甲中,設一個集合乙用來存放生成樹成長過程當中依次覆蓋的節點,記這棵生成樹年輕時爲T。(注意,這是個動態生長的樹,從0開始直到長成最小生成樹) Prim算法的基本流程(一個週期):(同kruskal同樣也是經過一個個簡單的循環來完成的) 首先,從甲中取出一個距離T最短的節點Q,就是乙中全部節點的全部外部鄰居中最近的那個點,若是是第一次循環的話就從甲中隨機取出一點。(如果並列最短就隨便選)。而後將這個點加入到乙中。以此循環直到甲空掉了爲止。 (@ο@) 哇~是否是感受比kruskal算法還要簡單直接,流程圖都不須要畫了(由於是一條筆直的直線流程),若是將各個循環結束時的狀態圖記錄下來,就會看到一棵生成樹從小長到大的過程。如同這個動態圖: 輸入圖片說明 ##有待調用的重要前提:教程

在證實prim算法以前咱們須要用到一個底層結論:在一個連通圖G中,對於每一個點,與本身相連的最短邊必定屬於G的生成樹。(若是有並列則任意一個最短邊) 這個結論very重要,想要證實他也很easy,仍是用萬能的反證法: 對於一個點Q它鏈接着m條邊,其中有一條最短邊L,G的最小生成樹T不通過L,那麼對於Q剩下m-1條邊中至少有一條邊鏈接Q與T,設有z條這樣的邊(0<z<m)。 那麼若是此時在T中把Q及Q鏈接的m條邊都移除,T剩下的部分將被分紅z個相互隔離的部分(生成樹的特性),並且Q關於L對稱的那個點有且只有屬於z個部分中的某一個部分。那麼問題來了,屬於的那個部分與Q相連的邊應當被替換成開銷更小的L,因此與T是最小生成樹矛盾,得以反證。 上圖解(圖中z=3): 輸入圖片說明 這樣就一清二楚了(吧?),圖中各個區域的「樹枝」符號就表明了被分割的部分樹,他們之間只能經過Q相通。因此Q的最短邊L必然在真正的生成樹中。圖片

##數學概括法證實:數學

有了這個結論後大勢已定,接下來我將展現用經典的數學概括法證實prim算法,其中以集合乙中的節點數量爲遞增變量(因此這裏的n是動態的),也能夠當作是動態增加的樹T。 n=1,選擇任意一個點Q1。 n=2,Q1發散到最近的Q2其中邊L1屬於最終最小生成樹T,成立。 假設n=k的時候成立,也就是Q1Q2Q3一直到Qk所在的T屬於最終最小生成樹。 那麼接下來作一個驚人之舉:把此時的T總體當作一個節點。爲何能夠這麼看呢,由於T和一個節點share共同的屬性:都是屬於最終生成樹;都有若干個與本身相連的邊。於是此舉不影響最後的生成樹。記住,最小生成樹的根本目的和原則就是千方百計不擇手段地用最少的邊鏈接最多的節點! 輸入圖片說明 當n=k+1的時候,從甲中剩下的節點中選擇距離T(點)最近的一條邊Lk加入到乙中,根據以前定理,T+Lk一塊兒也屬於最終生成樹。成立。 由數學概括法得證prim算法的正確性。完。it

##最後,兩種算法的異同變量

不難看出,兩種基本算法的內容都通俗易懂,只是證實起來略有困難。二者的區別在於,kruskal基於邊來收斂,而prim基於點。可是綜合來看prim要比kruskal高級一點,在邊數比較稠密的狀況下用prim求生成樹要快於kruskal,由於kruskal是一條邊一條邊來找的,畢竟prim使用和Dijkstra類似的「堆棧」思想而kruskal是一種貪心算法,當邊稀疏時二者均可適用。Anyway,兩者都是圖論學中很是重要的算法,你們務必牢記!循環

相關文章
相關標籤/搜索