最小生成樹的Prim算法以及Kruskal算法的證明


Prime算法的思路:從任何一個頂點開始,將這個頂點作為最小生成樹的子樹,通過逐步為該子樹添加邊直到所有的頂點都在樹中為止。其中添加邊的策略是每次選擇外界到該子樹的最短的邊添加到樹中(前提是無回路)。

Prime算法的正確性證明:

引理1:對於連通圖中的頂點vi,與它相連的所有邊中的最短邊一定是屬於最小生成樹的。

引理2:

證明:

假設最小生成樹已經建成;(vi, vj)是連接到頂點vi的最短邊,在最小生成樹中取出vi,斷開連接到vi的邊,則生成樹被拆分成

 

1、頂點vi

 

2、頂點vj所在的連通分量(單獨一個頂點也看作一個獨立的連通分量)

 

3、其余若干個連通分量(個數大於等於0)

 

三個部分

 

現在要重建生成樹,就要重新連接之前被斷開的各邊

 

雖然不知道之前被斷開的都是哪幾條邊,但是可以通過這樣一個簡單的策略來重建連接:將vi分別以最小的成本逐個連接到這若干個互相分離的連通分量;具體來說,就是要分別遍歷頂點vi到某個連通分量中的所有頂點的連接,然后選擇其中最短的邊來連接vi和該連通分量;而要將vi連接到vj所在的連通分量,顯然通過邊(vi, vj)連接的成本最低,所以邊(vi, vj)必然屬於最小生成樹(如果連接到vi的最短邊不止一條,只要任意挑選其中的一條(vi, vj)即可,以上的證明對於這種情況同樣適用)。

 

這樣我們就為原來只有一個頂點vi的子樹添加了一個新的頂點vj及新邊(vi, vj);接下來只要將這棵新子樹作為一個連通子圖,並且用這個連通子圖替換頂點vi重復以上的分析,迭代地為子樹逐個地添加新頂點和新邊即可。
Kruskal算法: 通過從小到大遍歷邊集,每次嘗試為最小生成樹加入當前最短的邊,加入成功的條件是該邊不會在當前已構建的圖中造成回路,當加入的邊的數目達到n-1,遍歷結束。
Kruskal算法的正確性證明:
Kruskal算法每次為當前的圖添加一條不會造成回路的新邊,其本質是逐步地連接當前彼此分散的各個連通分量(單個頂點也算作一個連通分量),而連接的策略是每次只用最小的成本連接任意兩個連通分量。這個策略之所以能夠實現,是因為每加入一條邊之后只會出現兩種結果:
1、在已有的連通分量中形成回路
2、連接兩個彼此獨立的連通分量
所以,通過從小到大遍歷邊集,判斷是否會造成回路,然后逐條添加新邊就可以實現上訴的連接策略
接下來需要證明的是,為什么每次用最小成本連接兩個連通分量,最后就可以生成一棵最小生成樹(畢竟每一個當前的最優解之和未必是全局的最優解)
借用在Prim算法中提到的那個判斷就可以很方便地證明:“如果某個連通圖屬於最小生成樹,那么所有從外部連接到該連通圖的邊中的一條最短的邊必然屬於最小生成樹”
通過這個判斷,可以很容易地證明:當最小生成樹被拆分成彼此獨立的若干個連通分量的時候,所有能夠連接任意兩個連通分量的邊中的一條最短邊必然屬於最小生成樹(因為該邊必然是這兩個連通分量的可以連接到外部的最短邊)。
由此也就證明了,Kruskal算法通過每次以最小的成本來連接兩個連通分量的策略確實可以正確地生成最小生成樹。
 
prim算法中如果用優先隊列來尋找距離一個點最近的點的話時間復雜度是O(ElogV),而Kruskal算法用STL::sort()函數對邊進行排序的復雜度是O(|E|log|E|),而並查集的復雜度是O(|E|),所以整個算法的時間大多花費在對邊進行排序上,總體時間復雜度大約是O(|E|log|E|),所以對於稠密圖來說prim算法更加有優勢,而對於稀疏圖來說,Kruskal算法更加有優勢。

 


免責聲明!

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



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