最小生成樹之普里姆(Prim)算法

Prim 算法是一種貪心算法(適合稠密圖)

設G=(V, E) 是無向連通帶權圖,V={0, 1, 2, ..., n-1};設最小生成樹 T=(U, E'),算法結束時 U=V,E'⊆E。

貪心選擇的思想是:每次對於還未加入到 U 中(即 V-U 中)所有點頂,從這些頂點中選擇一個頂點,選擇的標準是,它距離 U 最近(和 U 中某個頂點的權值最小),將這個頂點加入到 U 中,並將這條邊加入到 E' 中。當所有頂點都加入到了 U 中,算法結束。


C++代碼:

#include <iostream>
#include <cassert>
#include <limits>

using namespace std;

/*
* n : 圖的頂點個數
* u0:開始頂點
* C :帶權鄰接矩陣
*/
int prim(int n, int u0, int **C) {
    assert(n > 0 && u0 >= 0 && u0 < n);
    
    bool s[n];// 用於標記頂點是否加入到了 U 中
    int closest[n];// closest[i],表示 V-U 中的一個頂點 i,在 U 中的最近鄰接點 closest[i]
    int lowcost[n];// lowcost[i],表示 V-U 中的一個頂點 i,到 U 中所有頂點的最短邊的權值,即邊 <i, closest[i]> 的權值
    s[u0] = true;// 初始點默認已加入到 U 中
    for(int i=0; i < n; i++) {
        if(i != u0) {
            s[i] = false;// 初始化:其他所有的點都未加入到 U 中,都在 V-U 中
            closest[i] = u0;// 初始化:其他所有點,在 U 中的最近鄰近點,都是初始點
            lowcost[i] = C[u0][i];// 因此,它們對應的和 U 中的最短邊的權值即使與初始頂點的權值
        }
    }
    const int INFINITY = numeric_limits<int>::max();
    for(int i=0; i < n; i++) {// 在 V-U 中尋找距離 U 最近的頂點並更新 closest 和 lowcost
        int minWeight = INFINITY;
        int t = u0;
        for(int j=0; j < n; j++) {// 在 V-U 中尋找距離 U 最近的頂點 t
            if(!s[j] && lowcost[j]<minWeight) {
                t = j;
                minWeight = lowcost[j];
            }
        }
        if(t == u0)// 因爲 u0 在 U 中,如果在 V-U 中找到了,t 不可能爲 u0,爲 u0 表示沒有找到
            break;// 說明在 V-U 中沒有頂點和 U 中的任何一個頂點相鄰了,沒有必要再在 V-U 中繼續浪費時間了
        s[t] = true;// 找到這個點後,將其加入到 U 中
        for(int j=0; j < n; j++) {// 因爲 U 中加入了新的頂點,可能需要更新 V-U 中所有點頂的 closest 和 lowcost
            if(!s[j] && (C[t][j]<lowcost[j])) {
                lowcost[j] = C[t][j];
                closest[j] = t;
            }
        }
    }
    int cost = 0;
    for(int i=0; i < n; i++) {
        if(i != u0)
            cost += lowcost[i];
    }
    return cost;
}

int main() {
    int N;
    cin >> N;
    int **C = new int*[N];
    int minEdge = 0;
    int u0 = 0;
    for(int i=0; i < N; i++) {
        C[i] = new int[N];
        for(int j=0; j < N; j++) {
            cin >> C[i][j];
            if(minEdge > C[i][j]) {
                minEdge = C[i][j];
                u0 = i;
            }
        }
    }

    cout << prim(N, u0, C) << endl;

    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章