最小生成樹(prim演算法)

2021-07-16 06:55:29 字數 3411 閱讀 6562

在實際生活中我們常常會遇到這樣一些問題:有若干個需要連線的點(不妨假設為一些村莊)和若干條連線著兩個點的邊(在村莊間修公路),而這些邊會有不同的權值(可設為修路所需的費用不同)。現在要連通這些所有的點,並使權值和最小。這類問題在現實生活中很廣泛,如修公路、架設電網,等等。

在資訊學競賽中,這種問題有專門的稱謂「最小生成樹」(minimum spanning tree,簡稱mst)。

今天介紹一下mst問題中的prim演算法。首先來看一道例題。

題目描述: 

bessie受僱來到john的農場幫他們建立internet網路。農場有n (2(= n (= 1, 000)牛棚,編號為1. . n. john之前已經勘測過,發現有

m (1<=m<= 20, 000) 條可能的連線線路,一條線路是連線某兩個牛棚的。每條可能的線路都有乙個建 設如c (1<= c <=100,000). john當然想花盡量少的錢,甚至剋扣bessie的 工資。 

bessie發現了這點,很生氣,決定給john搗亂。她要

選擇)些線路組成網, 但費用卻盡可能大。當然網路要能正常工作,也就是

任意兩個牛棚之間都是相互 可以連通的,並且網路上不能有壞,不然john會很容易發現的。 

請計算組建這種網路最多可能的費用。 

輸入檔案cowtract. in 

第一行:兩個整數n m 

下面m行:每行3個整數a, b, c。表示乙個可能的線路要連線a、b兩個牛棚, 費用是c。

輸出檔案cowtract.out 

只一行,乙個整數,即花費最大的費用。如果不可能連線通所有牛棚,輸出-1。 

輸入樣例:

5 81 2 3

1 3 7

2 3 10

2 4 4

2 5 8

3 4 6

3 5 2

4 5 17

輸出樣例:

42注釋:

17+8+10+7=42

通過題目中紅色粗體字部分容易看出,本題是一道生成樹問題。不過有點不同,是「最大生成樹」。當然,演算法一樣。

現在,介紹一下prim演算法的思想。

首先我們可以確定,對於有n個頂點的圖,mst一定只有n-1條邊。如果有多餘的邊,顯然會造成浪費。

將圖分為兩個集合a和b,設a就是我們要求的mst。其中a一開始只有乙個任意的頂點。(整個圖最終是連通的,因而該頂點最後必定在mst中,可取任意一點。)

每次取a和b的最小權交叉邊e(即e=(x,y),x∈a且y∈b),將y加入a中。

當a中有n個頂點時,結束;否則轉3。

舉個例子:

此為原始的加權連通圖。每條邊一側的數字代表其權值。

頂點d被任意選為起始點。頂點a、b、e和f通過單條邊與d相連。a是距離d最近的頂點,因此將a及對應邊ad以高亮表示。

下乙個頂點為距離d或a最近的頂點。b距d為9,距a為7,e為15,f為6。因此,f距d或a最近,因此將頂點f與相應邊df以高亮表示。

演算法繼續重複上面的步驟。距離a為7的頂點b被高亮表示。

在當前情況下,可以在c、e與g間進行選擇。c距b為8,e距b為7,g距f為11。點e最近,因此將頂點e與相應邊be高亮表示。

這裡,可供選擇的頂點只有c和g。c距e為5,g距e為9,故選取c,並與邊ec一同高亮表示。

頂點g是唯一剩下的頂點,它距f為11,距e為9,e最近,故高亮表示g及相應邊eg。

現在,所有頂點均已被選取,圖中綠色部分即為連通圖的mst。在此例中,mst的權值之和為39。

**如下:

# include 

# define max(a,b) a>b?a:b //定義max巨集

const int size = 1000 + 5 ;

const int inf = 0x7fffffff ; //2^31-1

int n , m , dis[size] , g[size][size] , num[size] , f[size] ;

//dis[i]表示集合a中頂點到頂點i的最小權

//g是鄰接矩陣

//num[i]記錄頂點i的邊中權值最小的另一頂點

//f是並查集

bool visited[size] ;

//visited標記是否在mst中

//並查集操作

int _find ( int ) ;

void _union ( int , int ) ;

int main ()

bool liantong=true; //判斷是否連通

for ( int i=1 ; i!=n && liantong ; ++i )

if ( _find(f[i])!=_find(f[i+1]) ) liantong=false; //若最終不可能在同一集合中,必定無法連通

if ( !liantong )

for ( int i=0 ; i!=n+1 ; ++i )

int sum=0 ;

visited[1]=true ; //第1個頂點已在mst中

for ( int i=1 ; i!=n ; ++i )

}sum += g[num[k]][k] ;

visited[k]=true ; //入mst

for ( int j=1 ; j!=n+1 ; ++j ) }}

printf ( "%d\n" , sum ) ;

return 0 ;

}int _find ( int i )

void _union ( int i , int j )

upd(2015,12,31):prim演算法的時間複雜度為o(|v|^2)。

最小生成樹(prim演算法)

最小生成樹是資料結構中圖的一種重要應用,它的要求是從乙個帶權無向完全圖中選擇n 1條邊並使這個圖仍然連通 也即得到了一棵生成樹 同時還要考慮使樹的權最小。prim演算法要點 設圖g v,e 其生成樹的頂點集合為u。把v0放入u。在所有u u,v v u的邊 u,v e中找一條最小權值的邊,加入生成樹...

最小生成樹 Prim演算法

prim 演算法 以領接矩陣儲存 圖g bool b i 表示頂點i是否被訪問,初始化時候memset b,false,sizeof b b 0 value,表示從第0個節點開始。用value i 表示節點i到最小生成樹a中定點的最小距離。例如value 1 a 0 1 int sum記錄權值和 i...

最小生成樹 prim 演算法

一 演算法描述 假設存在連通帶權圖g v,e 其中最小生成樹為t,首先從圖中隨意選擇一點s屬於v作為起始點,並將其標記後加入集合u 中。然後演算法重複執行操作為在所有v屬於u,u屬於v u的邊 v0,u0 屬於e中找一條代價最小的邊並加入集合t,同時將u0併入u,直到u v為止。這是,t中必有n 1...