【圖(下)】最小生成樹問題
阿新 • • 發佈:2018-11-22
1、什麼是最小生成樹(Minimum Spanning Tree)
- 是一棵
樹
- 無迴路
- |V|個頂點一定有|V|-1條邊
- 是
生成
樹- 包含全部頂點
- |V|-1條邊都在圖裡
- 邊的權重和
最小
最小生成樹存在↔ 圖連通
2、貪心演算法
- 什麼是“貪”:每一步都要最好的
- 什麼是“好”:權重最小的邊
- 需要約束:
- 只能用圖裡有的邊
- 只能正好用掉|V|-1條邊
- 不能有迴路
3、Prim演算法— 讓一棵小樹長大
void Prim()
{
MST = { s };//s維護折樹中所有的頂點
while (1)
{
//dist值的含義為距離這棵樹的距離,樹節點dist為0;
//和樹相鄰節點dist為邊權重,不相鄰節點dist為無窮大。
V = 未收錄頂點中dist最小者;
if (這樣的V不存在)
break;
將V收錄進MST: dist[V] = 0;//dist設為0表示收入樹中
for (V 的每個鄰接點W)//收錄一個頂點會對該定點相鄰頂點dist有影響
if (W未被收錄)
if (E(V, W) < dist[W])
{
dist[ W] = E(V, W);
parent[W] = V;
}
}
if (MST中收的頂點不到 | V | 個)//圖不連通
Error(“生成樹不存在”);
}
Prim演算法中的dist[V]初始化:
dist[V] = E(s,V)或正無窮
parent[s] = -1
時間複雜度:
T = O( |V|2 ) 稠密圖合算
3、Kruskal演算法— 將森林合併成樹
圖中每一個頂點都可以看成一棵樹,每次找權重最小的邊,把它收進來。每次把邊收進來,就把兩棵樹併成一棵樹,最後把所有的節點併成一棵樹。
void Kruskal(Graph G)
{
MST = {};//生成樹集合中收集的元素為邊
while (MST 中不到 |V| -1 條邊&& E 中還有邊) {
從E中取一條權重最小的邊E(v, w);/* 最小堆*/
將E(v, w)從E中刪除;
if (E(V, W)不在MST中構成迴路)/* 並查集*/
將E(V, W) 加入MST;
else
徹底無視E(V, W);//生成樹不要該邊,E中也不要
}
if (MST 中不到 |V| -1 條邊)//圖不連通
Error(“生成樹不存在”);
}
-
從E中取一個權重最小的邊,將E中元素組織成一個
最小堆
,每次取出一條邊複雜度為log(E)。 -
判斷E(v,w)(表示從頂點V到頂點W的一條邊)的加入會不會在最小生成樹中構成迴路:
使用並查集
,加邊E(v,w)之前檢查頂點V和W,如果二者屬於不同的樹,不會構成迴路,在同一棵樹中則會構成迴路。
時間複雜度:
T = O( |E| log |E| )
對於稀疏圖比較划算