在實際生活中我們常常會遇到這樣一些問題:有若干個需要連線的點(不妨假設為一些村莊)和若干條連線著兩個點的邊(在村莊間修公路),而這些邊會有不同的權值(可設為修路所需的費用不同)。現在要連通這些所有的點,並使權值和最小。這類問題在現實生活中很廣泛,如修公路、架設電網,等等。
在資訊學競賽中,這種問題有專門的稱謂「最小生成樹」(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。
**如下:
# includeupd(2015,12,31):prim演算法的時間複雜度為o(|v|^2)。# 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 )
最小生成樹(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...