最小生成樹(MST,kruskal演算法)

2021-10-04 10:11:16 字數 1671 閱讀 4459

最小生成樹,對於乙個無向圖,聯通且不含圈的圖稱為樹。

給定無向圖g=(v,e),連線g中所有點,且邊集是e的子集的數稱為g的生成樹(spanning tree),而權值最小的生成樹稱為最小生成樹(minimal spanning tree, mst)。構造mst的演算法有很多,最常見的有兩個:kruskal演算法和prim演算法。這裡只介紹kruskal演算法,因為這個演算法編寫容易且效率很高。

前面描述不清楚的話,可以看下圖

這是乙個無向圖,每條邊有權重,你可以採用幾條邊就能連線所有的點,就得到了一顆生成樹(前提是不含圈)。如果樹的所有邊的權值之和最小,就稱為最小生成樹。

kruskal演算法的流程非常簡單和直接:

其中第2步可能出現環,則需要檢驗環,這裡可以採用dfs或者bfs的方式進行圖遍歷(寫起來很複雜,需要判斷什麼樣才算是環,而且複雜度很高)。所以我們採用另外一種方式來進行檢驗,那就是"並查集"。並查集可以檢視我之前的博文並查集解釋。

另外第2步會出現的情況就是已經有幾個邊入選但是構不成樹,如下圖所示:

事實上我們並不需要馬上構成樹,我們只需要將邊選出來,然後構造點的集合就可以了,這也就是為什麼要用並查集的另乙個理由,例如上圖中有三個集合,分別是,,。如果連同了,那兩個集合就合併為乙個集合。其他還沒有邊連線的點構成另外的集合,例如,,…

那並查集如何判斷環呢?其實只要判斷邊的兩個端點(u,v)是否在同乙個集合中,如果在同乙個集合中,說明已經聯通(構成樹),你再新增就會構成環。

以上,kruskal演算法應該解釋清楚了。

struct edge;}

;// 邊的結構體,其他可能有不同

bool

cmp(edge e1, edge e2)

// 比較函式

//以下是並查集

int pre[n]

;//記錄每個點的父節點, n個節點

intunionsearch

(int root)

return root;

//返回根節點

}void

join

(int root1,

int root2)

//合併函式

edge e[nmax]

;// 預設已經讀取完畢,並且邊的個數就是nmax

intkruskal()

if(!pre[to])if

(unionsearch

(from)

!=unionsearch

(to)

)//這條邊兩個點不屬於同乙個集合,那就合併

join

(from, to)

;else

continue

; total_cost +

= cost;

if(total_num==n)

//全部加入,退出

break;}

return total_cost;

}

條件有限就直接記事本敲了,如果有錯誤還請告知

最小生成樹(MST) Kruskal演算法

kruskal演算法是在處理乙個森林 樹的集合。開始時將圖的每個頂點看做一棵樹 集合 然後採用貪婪策略,每次從所有邊中依次選出 find 權值最小的邊,當改邊的兩個端點不在同一集合時,則將終點所在集合與起點集合合併 union 直到依次處理完所有的邊,演算法終止,此時所有的頂點在乙個樹中,即為最小生...

最小生成樹(MST) Kruskal演算法

kruskal演算法主要對邊進行貪心,經過變換還可以求最大生成樹,還可以記錄樹的具體路徑。初始狀態時隱去圖中所有邊,這樣圖中每個頂點都自成乙個連通塊。對所有邊權從小到大排序。按邊權從小到大測試所有邊,如果當前測試邊所連線的兩個結點不在同乙個連通塊中,則把這條測試邊加入最小生成樹中 合併兩個連通塊 否...

最小生成樹 次小生成樹

一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...