Prim 演算法及其高效實現
背景
最小生成樹(Minimum Spanning Trees),簡稱MST。是圖論中一個非常重要的概念。解決這個問題有兩種演算法,今天暫且先來討論一下Prim Algorithm。不做特別說明,討論的都是無向圖。
首先介紹一下最小生成樹的概念,我們知道,圖可以這樣定義 G=(V,E) ,其中 G 表示圖,V 表示頂點集合,E 表示邊集合。最小生成樹是這樣一棵樹,它滿足:
通俗地講,就是使得圖GG連通時,所選取的邊的長度的和最小。
如上圖,加粗的路徑就是在最小生成樹上的路徑。
演算法講解:
現在,我們開始討論Prim Algorithm。這個演算法可以分為下面幾個步驟:
將頂點集 V 分成兩個集合 A 和 B,其中集合 A 表示目前已經在MST中的頂點,而集合 B 則表示目前不在 MST 中的頂點。
尋找與集合 A 連通的最短的邊 (u,v),將這條邊加入最小生成樹中。(此時,與(u,v) 相連的頂點,不妨設為 Bi,也應加入集合 A 中)重複第二步,直至集合 B 為空集。
演算法的大體思想就是這樣了。為了方便理解,我們先來看一下下面一張圖片:
對照上面的圖片,想必對於Prim Algorithm也有了一定的理解。
下面我們來設計演算法,顯然,我們需要遍歷集合 A 中所有頂點及與之相連的邊,取連線到集合B的權值最小的邊,加入最小生成樹。這樣一來,複雜度將達到 O(n3)。
我們可以對這個想法進行優化。我們維護一 pCost[i] 陣列,用來表示從集合A到與之相鄰的節點的最小費用。這樣,我們只要每次取這個陣列中的最小值,把它在集合B中所對應的結點Vi加入到集合A中。
每次加入結束以後,都要更新pCost[i]陣列。即列舉所有與結點Vi相連的邊,判斷是否比pCost[i]陣列中的最小費用小,如果比它小,則更新。這樣可以將演算法優化到O(n2)。
程式碼如下:
#include <iostream>
#include <memory.h>
#include <vector>
using namespace std;
const int MAX = 1024;
const int INF = 2147483647;// 設定最大權值
int N, M;
vector<pair<int, int> > pMap[MAX];// 鄰接表
void Prim();
int main()
{
cin >> N >> M;
for(int i = 1; i <= M; i++)
{
int u, v, w;
cin >> u >> v >> w;
pMap[u].push_back(make_pair(v, w));
pMap[v].push_back(make_pair(u, w));
}
Prim();
return 0;
}
void Prim()
{
int nCost = 0;
vector<int> pMST;// 儲存MST的結點
int pCost[MAX];// 儲存與集合A相鄰的頂點的最小權值,0表示該結點已經在MST中
pMST.push_back(1);// 將結點1加入MST
pCost[1] = 0;
for(int i = 2; i <= N; i++)// 初始化,切記要將除1以外的都置為INF
{ pCost[i] = INF; }
for(int i = 0; i < pMap[1].size(); i++)// 處理與結點1相連的頂點
{ pCost[pMap[1][i].first] = pMap[1][i].second; }
for(int i = 1; i <= N - 1; i++)// 剩餘N-1個頂點,迴圈N-1次
{
int nVertex = 0, nWeight = INF;// 用於尋找最短的邊
for(int j = 1; j <= N; j++)
{
if(nWeight > pCost[j] && pCost[j] != 0)
{
nVertex = j;
nWeight = pCost[j];
}
}
pCost[nVertex] = 0;
pMST.push_back(nVertex);// 將節點nVertex加入MST
nCost += nWeight;// 計算MST的費用
for(int j = 0; j < pMap[nVertex].size(); j++)// 更新pCost陣列
{
if(pCost[pMap[nVertex][j].first] != 0 &&
pCost[pMap[nVertex][j].first] > pMap[nVertex][j].second)
{
pCost[pMap[nVertex][j].first] = pMap[nVertex][j].second;
}
}
}
cout << "MST Cost is " << nCost << endl;
cout << "The vertexs in MST are ";
for(int i = 0; i < pMST.size(); i++)
{ cout << pMST[i] << " "; }
cout << endl;
}
轉自:ivy-end
http://www.ivy-end.com/archives/943