演算法思想(八) 最小生成樹

2021-09-24 11:40:26 字數 4293 閱讀 5266

稠密圖

//稠密圖-鄰接矩陣

template

class densegraph

//析構函式

~densegraph()

//返回節點個數

intv()

//返回邊的個數

inte()

//向圖中新增乙個邊,權值為weight

void

addedge

(int v,

int w,weight weight)

g[v]

[w]= new edge

(v,w,weight);if

(v!=w &&

!directed)

g[w]

[v]= new edge

(w,v,weight)

; m++;}

//驗證圖中是否有從v到w的邊

bool hasedge

(int v,

int w)

//顯示圖的資訊

void

show()

cout<

//鄰邊迭代器,傳入乙個圖和乙個頂點

//迭代在這個圖中和這個頂點相連的所有邊

class adjiterator

~adjiterator()

//f返回圖g中與頂點v相連線的第乙個邊

edge

*begin()

//返回圖g中與頂點v相連線的下乙個邊

edge

*next()

//檢視是否已經迭代完了圖g中與頂點v相連線的所有邊

bool end()

};};

稀疏圖

//稀疏圖

template

class sparsegraph

~sparsegraph()

//返回節點個數

intv()

//返回邊的個數

inte()

//向圖中新增乙個邊,權值為weight

void

addedge

(int v,

int w,weight weight)

//驗證圖中是否有從v到w的邊

bool hasedge

(int v,

int w)

void

show()

}//鄰邊迭代器,傳入乙個圖和乙個頂點

//迭代在這個圖中和這個頂點相連的所有邊

class adjiterator

//返回圖g中與頂點v相連線的第乙個邊

edge

*begin()

//返回圖g中與頂點v相連線的下乙個邊

edge

*next()

bool end()

};};

切分定理(cut property)

把圖中的結點分為兩部分,成為乙個切分(cut)

如果乙個邊的兩個端點,屬於切分(cut)不同的兩邊,這個邊稱為橫切邊

切分定理:給定任意切分,橫切邊中權值最小的邊必然屬於最小生成樹

lazy prime:

在這裡選取權值最小的邊的時候要利用到最小堆(之前講過)

以下為prime演算法:

//使用prim演算法求圖的最小生成樹

template

class lazyprimmst

public:

//建構函式,使用prim求圖的最小生成樹

lazyprimmst

(graph &graph):g

(graph),pq

(minheap

>

(graph.e(

)))//計算最小生成樹的權值

mstweight = mst[0]

.wt()

;for

(int i=

1;isize()

;i++

) mstweight+

=mst[i].wt

();}

//析構函式

~lazyprimmst()

//返回最小生成樹的所有邊

vector

>

mstedges()

//返回最小生成樹的權值

weight result()

};#endif

// lazyprimmst_h_included

測試**:

// 測試有權圖和有權圖的讀取

intmain()

執行結果:

進行優化使之時間複雜度為o(elo**)

維護乙個indexminheap資料結構

最小索引堆中的元素個數和圖中的頂點個數一致,在堆操作這裡提高了效率,遍歷邊的次數也變小了。

//使用優化的prim演算法求圖的最小生成樹

template

class primmst

//如果考慮過這個端點,但現在的邊比之前考慮的邊更短,則進行替換

else

if(e->wt(

)->wt(

))}}

}public:

//建構函式,使用prim演算法求圖的最小生成樹

primmst

(graph &graph):g

(graph)

,ipq

(indexminheap<

double

>

(graph.v(

))) mst.

clear()

;//prim

visit(0

);while

(!ipq.

isempty()

) mstweight = mst[0]

.wt()

;for

(int i=

1;isize()

;i++

) mstweight+

=mst[i].wt

();}

~primmst()

vector

>

mstedges()

weight result()

};#endif

// primmst_h_included

思路:每次都找最短的那邊條,只要不構成環,那條邊一定是最小生成樹的邊。

為什麼呢?因為根據這條最短邊,我們總能找到乙個切分,使得該邊為這個切分下的橫切邊的最短邊。

如果判斷加入邊後有沒有環的存在呢?使用並查集

//kruskal演算法

template

class kruskalmst

//建立乙個並查集,來檢視已經訪問的節點的聯通情況

unionfind uf =

unionfind

(graph.v(

));while

(!pq.

isempty()

&& mst.

size()

< graph.v(

)-1)

mstweight = mst[0]

.wt()

;for

(int i=

1;isize()

;i++

) mstweight+

=mst[i].wt

();}

~kruskalmst()

//返回最小生成樹的所有邊

vector

>

mstedges()

//返回最小生成樹的權值

weight result()

};#endif

// kruskalmst_h_included

最小生成樹問題如果橫切邊有相等的邊,根據演算法的具體實現,每次選擇乙個邊,此時,圖存在多個最小生成樹。

延伸問題:對於乙個圖有多少個最小生成樹??

vessotsky『s algorithm

將邊逐漸的新增到生成樹中,一旦形成環,刪除環中權值最大的邊(難度比較大)。

最小生成樹演算法

由帶權的連通圖生成的數的各邊加起來稱為生成樹的權,把權值最小的生成樹稱為最小生成樹 minimum spanning tree 簡稱為mst 構造最小生成樹的方法就是利用mst性質,一條一條地選擇可以加入的邊。下面介紹兩種用於構造最小生成樹的演算法,其中第一種演算法稱為prim演算法,第二種演算法稱...

最小生成樹演算法

乙個最簡單的最小生成樹 圖結構練習 最小生成樹 time limit 1000ms memory limit 65536k 有n個城市,其中有些城市之間可以修建公路,修建不同的公路費用是不同的。現在我們想知道,最少花多少錢修公路可以將所有的城市連在一起,使在任意一城市出發,可以到達其他任意的城市。輸...

演算法 最小生成樹

前言 最小生成樹是在乙個給定的無向圖中求一棵樹,這棵樹包含無向圖中的所有頂點,且樹中的邊都來自無向圖中的邊,並且要滿足整棵樹的邊權之和最小。1 最小生成樹是樹,其邊數等於頂點數減1,且不會有環 2 對於給定的圖最小生成樹可以不唯一,但是邊權之和一定是唯一的。3 其根節點可以是這棵樹上的任何乙個節點,...