1. 程式人生 > >prim演算法模板—最小生成樹

prim演算法模板—最小生成樹

        設G = (V,E)是無向連通帶權圖,即一個網路。E中的每一條邊(v,w)的權為c[v][w]。如果G的子圖G’是一棵包含G的所有頂點的樹,則稱G’為G的生成樹。生成樹上各邊權的總和稱為生成樹的耗費。在G的所有生成樹中,耗費最小的生成樹稱為G的最小生成樹。構造最小生成樹的兩種方法:Prim演算法和Kruskal演算法

 一、最小生成樹的性質

  設G = (V,E)是連通帶權圖,U是V的真子集。如果(u,v)∈E,且u∈U,v∈V-U,且在所有這樣的邊中,(u,v)的權c[u][v]最小,那麼一定存在G的一棵最小生成樹,它意(u,v)為其中一條邊。這個性質有時也稱為MST性質。

 二、Prim演算法(與dijkstra演算法很相似)

  設G = (V,E)是連通帶權圖,V = {1,2,…,n}。構造G的最小生成樹Prim演算法的基本思想是:首先置S = {1},然後,只要S是V的真子集,就進行如下的貪心選擇:選取滿足條件i ∈S,j ∈V – S,且c[i][j]最小的邊,將頂點j新增到S中。這個過程一直進行到S = V時為止。在這個過程中選取到的所有邊恰好構成G的一棵最小生成樹。

如下帶權圖:

生成過程

1 -> 3 : 1

3 -> 6 : 4

6 -> 4: 2

3 -> 2 : 5

2 -> 5 : 3

C語言程式碼:

void Prim(){
	int i,j,k,tmp,ans;
	for(i=1;i<=n;i++)
	dis[i]=inf;//初始化 
	dis[1]=0;
	for(i=1;i<=n;i++){
		tmp=inf;
		for(j=1;j<=n;j++){
			if(!vis[j]&&tmp>dis[j]){
				tmp=dis[j];
				k=j;
			}//找出最小距離的節點 
		}
		vis[k]=1;//把訪問的節點做標記
		for(j=1;j<=n;j++){
			if(!vis[j]&&dis[j]>map[k][j])
			dis[j]=map[k][j];//更新最短距離 
		}
	}
}

三、Kruskal演算法

       當圖的邊數為e時,Kruskal演算法所需的時間是O(eloge)。當e = Ω(n^2)時,Kruskal演算法比Prim演算法差;但當e = o(n^2)時,Kruskal演算法比Prim演算法好得多

給定無向連同帶權圖G = (V,E),V = {1,2,...,n}。Kruskal演算法構造G的最小生成樹的基本思想是:

1)首先將G的n個頂點看成n個孤立的連通分支。將所有的邊按權從小大排序。

(2)從第一條邊開始,依邊權遞增的順序檢查每一條邊。並按照下述方法連線兩個不同的連通分支:當檢視到第k條邊(v,w)時,如果端點v和w分別是當前兩個不同的連通分支T1和T2的端點是,就用邊(v,w)將T1和T2連線成一個連通分支,然後繼續檢視第k+1條邊;如果端點v和w在當前的同一個連通分支中,就直接再檢視k+1條邊。這個過程一個進行到只剩下一個連通分支時為止。

此時,已構成G的一棵最小生成樹。

Kruskal演算法的選邊過程

1 -> 3 : 1

4 -> 6 : 2

2 -> 5 : 3

3 -> 4 : 4

2 -> 3 : 5