Prim算法
1.概覽
普里姆算法(Prim算法),圖論中的一種算法,可在加權連通圖裏搜索最小生成樹。意即由此算法搜索到的邊子集所構成的樹中,不但包括了連通圖裏的所有頂點,且其所有邊的權值之和亦爲最小。該算法於1930年由捷克數學家沃伊捷赫·亞爾尼克發現;並在1957年由美國計算機科學家羅伯特·普里姆獨立發現;1959年,艾茲格·迪科斯徹再次發現了該算法。因此,在某些場合,普里姆算法又被稱爲DJP算法、亞爾尼克算法或普里姆-亞爾尼克算法。
2.算法簡單描述
1).輸入:一個加權連通圖,其中頂點集合爲V,邊集合爲E;
2).初始化:Vnew = {x},其中x爲集合V中的任一節點(起始點),Enew = {},爲空;
3).重複下列操作,直到Vnew = V:
a.在集合E中選取權值最小的邊<u, v>,其中u爲集合Vnew中的元素,而v不在Vnew集合當中,並且v∈V(如果存在有多條滿足前述條件即具有相同權值的邊,則可任意選取其中之一);
b.將v加入集合Vnew中,將<u, v>邊加入集合Enew中;
4).輸出:使用集合Vnew和Enew來描述所得到的最小生成樹。
下面對算法的圖例描述
下面對算法的圖例描述
圖例 | 說明 | 不可選 | 可選 | 已選(Vnew) |
---|---|---|---|---|
此爲原始的加權連通圖。每條邊一側的數字代表其權值。 | - | - | - | |
頂點D被任意選爲起始點。頂點A、B、E和F通過單條邊與D相連。A是距離D最近的頂點,因此將A及對應邊AD以高亮表示。 | C, G | A, B, E, F | D | |
下一個頂點爲距離D或A最近的頂點。B距D爲9,距A爲7,E爲15,F爲6。因此,F距D或A最近,因此將頂點F與相應邊DF以高亮表示。 | C, G | B, E, F | A, D | |
算法繼續重複上面的步驟。距離A爲7的頂點B被高亮表示。 | C | B, E, G | A, D, F | |
在當前情況下,可以在C、E與G間進行選擇。C距B爲8,E距B爲7,G距F爲11。E最近,因此將頂點E與相應邊BE高亮表示。 | 無 | C, E, G | A, D, F, B | |
這裏,可供選擇的頂點只有C和G。C距E爲5,G距E爲9,故選取C,並與邊EC一同高亮表示。 | 無 | C, G | A, D, F, B, E | |
頂點G是唯一剩下的頂點,它距F爲11,距E爲9,E最近,故高亮表示G及相應邊EG。 | 無 | G | A, D, F, B, E, C | |
現在,所有頂點均已被選取,圖中綠色部分即爲連通圖的最小生成樹。在此例中,最小生成樹的權值之和爲39。 | 無 | 無 | A, D, F, B, E, C, G |
3.簡單證明prim算法
反證法:假設prim生成的不是最小生成樹
1).設prim生成的樹爲G0
2).假設存在Gmin使得cost(Gmin)<cost(G0) 則在Gmin中存在<u,v>不屬於G0
3).將<u,v>加入G0中可得一個環,且<u,v>不是該環的最長邊(這是因爲<u,v>∈Gmin)
4).這與prim每次生成最短邊矛盾
5).故假設不成立,命題得證.
#include<iostream>
#include<vector>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
const int MAX = 10;
int n ,k;
struct Edge{
int k;
int w;
Edge(int kk, int ww)
:k(kk), w(ww){
}
Edge(){
};
};
vector<Edge> G[MAX];
int dist[MAX];
int addvnew[MAX];
//int adjecent[MAX];
/*
7 11
1 2 7
1 4 5
2 3 8
2 4 9
2 5 7
3 5 5
4 5 15
4 6 6
5 6 8
5 7 9
6 7 11
*/
int prim(int s)
{
int sum = 0;
for(int i = 0; i < MAX; ++i){
dist[i] = INF;
addvnew[i] = 0;
}
for(int i = 0;i < G[s].size(); ++i){
dist[G[s][i].k] = G[s][i].w;
}
addvnew[s] = 1;
// adjecent[s] = s;
for(int i = 1;i <= n ; ++i){
if(i != s){
int min = INF;
int v = -1;
for(int j = 1; j <= n; ++j){
if(!addvnew[j] && dist[j] < min){
min = dist[j];
v = j;
}
}
if(v != -1){
//cout << adjecent[v] << v << dist[v] << "\n";
addvnew[v] = 1;
sum += dist[v];
for(int j = 0;j < G[v].size(); ++j){
if(!addvnew[G[v][j].k] && G[v][j].w < dist[G[v][j].k]){
dist[G[v][j].k] = G[v][j].w ;
// adjecent[G[v][j].k] = v;
}
}
}
}
}
cout << "minmum sum:" << sum << "\n";
}
int main()
{
cin >> n >> k;
int a, b, w;
while(k--){
cin >> a >> b >> w;
G[a].push_back(Edge(b,w));
G[b].push_back(Edge(a,w));
}
prim(4);
}