1. 程式人生 > >最小生成樹prim演算法與kruskal演算法

最小生成樹prim演算法與kruskal演算法

最小生成樹:在連通網的所有生成樹中,所有邊的代價和最小的生成樹,稱為最小生成樹。
這裡寫圖片描述
分析:從一個初始點開始,每次獲取與該點直連的點,並與之前獲取的可連線的邊比較,得到最小邊,然後將連線的點併入集合(以後的點不能在包括他,要不然會形成迴路),直到遍歷完所有頂點糾結束。
程式碼:

#include<iostream>
const int INF = 10000;
using namespace std;
const int N = 6;
bool visit[N];
int dist[N] = { 0 };
int g[N][N] = { { INF, 6, 1, 5, INF, INF },  //INF代表兩點之間不可達  
{ 6, 5, INF, INF, 3, INF }, { 1, 5, INF, 5, 6, 4 }, { 5, INF, 5, INF, INF, 2 }, { INF, 3, 6, INF, INF, 6 }, { INF, INF, 4, 2, 6, INF } }; int prim(int cur){ int index = cur; int sum = 0; for (int i = 0; i < N; i++){ dist[i] = g[cur][i];//獲取所有點與第一個點的距離 } memset(visit, false
, sizeof(visit)); visit[cur] = true;//第一個點不能再包括 cout << index << " ";//輸出第一個點 for (int i = 1; i < N; i++){ int minor = INF; for (int j = 0; j < N; j++){//尋找最短邊 if (!visit[j] && dist[j] < minor){ minor = dist[j]; index = j; } } visit[index] = true
;//最短邊對應的另一個點納入集合 cout << index << " "; sum += minor;//最小樹的總距離長度 for (int j = 0; j < N; j++){ if (!visit[j] && dist[j]>g[index][j]){//更新當前包括之前可連的點(最短),當前這個點a與其他點b的距離可能比之前的其他點c與點b的距離要短,所以要更新。 dist[j] = g[index][j]; } } } cout << endl; return sum; } int main(void){ cout << prim(0) << endl; system("pause"); return 0; }

給自己留個坑,還有個kruskal演算法也是求最小樹的,大體思路就是用並查集來做,我現在還沒開始寫,之後補上。
思路:
把所有的線段以不降序列排序,然後從小到大遍歷線段的兩個節點,若兩個節點不屬於同一個集合,即不會形成迴路,可以納入集合,方法使用並查集的相關操作,
寫好了,程式碼附上:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100;
struct node {
    int a, b, l;//線段的頭結點和尾節點和長度
    bool operator<(node n1) {
        return n1.l > this->l;//以長度做不降序列
    }
};
node arr[N];
int parent[N], dist[N];//父節點和節點數
int m, n;
void creat() {
    for (int i = 0; i < n; i++) {
        parent[i] = i;
        dist[i] = 1;
    }
}
int find(int cur) {//查詢根節點值
    if (parent[cur] != cur)parent[cur] = find(parent[cur]);
    return parent[cur];
}
void _union(int x, int y) {//合併節點
    int r1, r2;
    r1 = find(x); r2 = find(y);
    if (dist[r1] > dist[r2]) {//按秩合併,將節點數少的放在節點數多的下面
        parent[r2] = r1;
    }
    else if (dist[r1] < dist[r2]) {
        parent[r1] = r2;
    }
    else {
        parent[r1] = r2;
        dist[r2]++;
    }
}
void kruskal() {
    creat();
    int sum = 0;
    for (int i = 0; i < n; i++) {
        int x = arr[i].a, y = arr[i].b;
        if (find(x) != find(y)) {//如果兩節點不在同一集合就可以合併
            sum += arr[i].l;
            _union(x, y);
        }
    }
    cout << sum<<endl;
}

int main(void) {
    cin >> m >> n;
    for (int i = 0; i < n; i++) {
        cin >> arr[i].a >> arr[i].b >> arr[i].l;
    }
    sort(arr, arr + n);
    kruskal();
    system("pause");
    return 0;
}