最小生成樹,Prim演算法與Kruskal演算法,408方向,思路與實現分析

ZaunEkko發表於2021-05-30

最小生成樹,Prim演算法與Kruskal演算法,408方向,思路與實現分析

最小生成樹,老生常談了,生活中也總會有各種各樣的問題,在這裡,我來帶你一起分析一下這個演算法的思路與實現的方式吧~~

在考研中呢,最小生成樹雖然是隻考我們分析,理解就行,但我們還是要知道底層是怎麼實現的,話不多說,進入正題~~

什麼是生成樹?什麼是最小生成樹

總所周知,對於一個無向連通圖,我們想把他看成一個樹的話,那麼就不能太亂,也就引出了,如果對於一個生成樹(不唯一,滿足條件即可),如果砍去它的一條邊,則會變成非連通圖,如果加上一條邊則會形成一個迴路,也就是包含圖的全部頂點的一個極小連通子圖,如下所示~~

圖片

因此,對於頂點數為n的圖,生成樹應含有n-1條邊~~

那麼,最小生成樹又是什麼呢?

當邊帶權時,我們想要一個生成樹,使得帶權路徑和最小,那麼這樣的生成樹就被我們稱作最小生成樹(不唯一),也就是邊的權值之和最小的生成樹(MST,Minimum-Spanning-Tree)~~

那麼怎麼求一個最小生成樹呢?

沒錯,我們相求一個最小生成樹,我們的前輩大牛也想過這個問題,也就引出了兩個演算法,一個是Prim演算法(普里姆),和Kruskal演算法(克魯斯卡爾)~~

先給一個案例我們來分析一下,經典的修路~~

我們想要使得我們這個小鎮全都連通,但又花費經濟最少(虛線邊數值代表所需金錢,也就是權值),該怎麼修呢?先給出答案,接下來我們用兩個演算法分別分析一下思路以及底層實現~~

圖片

Prim演算法(普里姆)思路分析與底層實現

Prim演算法:從選取的某一個頂點開始,每次將代價最小的新頂點納入生成樹,直到所有頂點都納入為止~~

思路分析:也就是並查集內加新頂點,為了方便理解,我們把並查集每次都納入的頂點看成一個在一個圈裡加入新頂點,不屬於圈裡的即為連通的頂點,如圖所示演算法思路~~

圖片

底層實現:我們這裡定義兩個陣列一個為isJoin[]和lowCost[]陣列,isJoin[]用來標記是否已加入樹,lowCost[]用來表示各節點加入當前樹時的最低代價~~

如第一個步驟的時候,只有c點加入了樹,那麼我們就當c點已經加入了樹,也就是說isJoin[6]變為了如表所示(為了方便我們把陣列下標換成我們的字母abcdef)~~

C A B D E F
isJoin[6] 1 0 0 0 0 0

此時我們的lowCost[6]對應就應為(沒有邊直接連通則為無窮):

C A B D E F
lowCost[6] 0 1 5 4 6 4

lowCost最小為1,也就是C與A連線所需代價最小,所以當第1步結束時,我們將A連入樹中,修改對應isJoin[6]和lowCost[6]~~

C A B D E F
isJoin[6] 1 1 0 0 0 0
C A B D E F
lowCost[6] 0 0 5 4 6 4

權:1~~

lowCost最小為4,也就是(D或者F)與圈AC連線所需代價最小,所以當第2步結束時,我們將F連入樹中,修改對應isJoin[6]和lowCost[6]~~

C A B D E F
isJoin[6] 1 1 0 0 0 1
C A B D E F
lowCost[6] 0 0 5 2 6 0

權:1+4~~

因為現在要和圈ACF連線,D如果想代價最小就可以選擇DF連線(2),而不是以前的DC連線(4),2代價更小,這就是lowCost[]用來表示各節點加入當前樹時的最低代價的意思~~

重複此過程~~

C A B D E F
isJoin[6] 1 1 0 1 0 1
C A B D E F
lowCost[6] 0 0 5 0 6 0

權:1+4+2~~

接下來

C A B D E F
isJoin[6] 1 1 1 1 0 1
C A B D E F
lowCost[6] 0 0 0 0 3 0

權:1+4+2+5~~

最後

C A B D E F
isJoin[6] 1 1 1 1 1 1
C A B D E F
lowCost[6] 0 0 0 0 0 0

權:1+4+2+5+3=15~~

Kruskal演算法(克魯斯卡爾)思路分析與底層實現

雙生關係,Prim是每次選一個連到樹裡代價最小的頂點構成一個樹,Kruskal是每次選一條權值最小的邊,使這條邊兩端連通(如果原本就已經連通就不選),直到所有結點都連通~~

思路分析:上圖~~

圖片

底層實現:並查集~~

按權值排序~~

weight 1 2
1 A C
2 D F
3 B E
4 D C
4 C F
5 A D
5 B C
6 A B
6 C E
6 E F

依次往下看,1和2兩個點是否屬於同一集合(先規定所有頂點都屬於不同的集合,如果兩個頂點相連,則這兩個頂點構成了一個集合)~~

如第一次,weight為1,A和C為不同集合,相連,通過~~(集合AC,B,D,E,F)

第二次,weight為2,D和F為不同集合,相連,通過~~(集合AC,DF,B,E)

第三次,weight為3,B和E為不同集合,相連,通過~~(集合AC,DF,BE)

第四次,weight為4,D和C雖然DF是一個集合,AC是一個集合,但DF和AC不是一個集合裡的不連通,所以相連,通過~~(集合ACDF,BE)

第五次,weight為4,C和F同屬於ACDF集合裡,所以不相連,不通過~~(集合ACDF,BE)

第六次,weight為5,A和D同屬於ACDF集合裡,所以不相連,不通過~~(集合ACDF,BE)

第七次,weight為5,B和C不屬於同一個集合裡,所以相連,通過~~(集合ABCDEF)

至此成功~~

最小生成樹還是簡單的,為我們後面學習最短路徑做基礎,這裡大家好好看看,下週我就來談一談最短路徑的幾個演算法,這兩者很像,但要區分開來~~

相關文章