1. 程式人生 > >圖的最小生成樹Kruskal演算法

圖的最小生成樹Kruskal演算法

克魯斯卡爾(Kruskal)演算法(只與邊相關)

演算法描述:克魯斯卡爾演算法需要對圖的邊進行訪問,所以克魯斯卡爾演算法的時間複雜度只和邊又關係,可以證明其時間複雜度為O(eloge)。
演算法過程:
1.將圖各邊按照權值進行升序排序
2.將圖遍歷一次,找出權值最小的邊,(條件:此次找出的邊不能和已加入最小生成樹集合的邊構成環),若符合條件,則加入最小生成樹的集合中。不符合條件則繼續遍歷圖,尋找下一個最小權值的邊。
3.遞迴重複步驟1,直到找出n-1條邊為止(設圖有n個結點,則最小生成樹的邊數應為n-1條),演算法結束。得到的就是此圖的最小生成樹。

克魯斯卡爾(Kruskal)演算法因為只與邊相關,則適合求稀疏圖的最小生成樹。而prime演算法因為只與頂點有關,所以適合求稠密圖的最小生成樹。
具體演算法如下:有用到並查集的演算法思想,具體可以自己百度“並查集”瞭解

#include <iostream>
#include <algorithm>
using namespace std;

struct edge      //邊結構,儲存邊的兩個節點及邊的長度
{
    int start_point;
    int end_point;
    int length;
};

const int N = 100;  //設定最多的節點數為100
edge Edge[N];
int pre[N];         //pre陣列儲存節點的根節點資訊,初始化為本身

bool cmp(edge a, edge b)   //排序函式的比較因子,按照邊的長度、節點序號的升序排列
{ if (a.length == b.length) { if (a.start_point == b.start_point) { return a.end_point < b.end_point; } else return a.start_point < b.start_point; } else return a.length < b.length; } int find(int x) //查詢節點x的根節點,並進行路徑壓縮,具體細節可以百度“並查集”
{ int r = x; while (pre[r] != r) { r = pre[r]; } int i = x; int j; while (i != r) { j = pre[i]; pre[i] = r; i = j; } return r; } int main() { int n, m, i, j, k, v, w; int s, e, length; int sum = 0; cin >> n; //輸入邊的數目 for (i=0; i<n; ++i) //初始化,儲存邊的資訊,節點號我們按照從1開始 { cin >> s >> e >> length; Edge[i+1].start_point = s; Edge[i+1].end_point = e; Edge[i+1].length = length; } for (i=0; i<n; ++i) { pre[i+1] = i + 1; //初始化節點根節點資訊 } sort(Edge+1,Edge+n+1,cmp); //對邊的資訊按照長度升序排序 for (i=0; i<n; ++i) //遍歷所有的邊 { k = Edge[i+1].start_point; v = Edge[i+1].end_point; k = find(k); v = find(v); if (k != v) ////查詢這條邊的兩個節點是否位於同一個連通分支,若不是,則將該邊加入進去,並將它們的根節點連通起來(pre[k] = v) { sum += Edge[i+1].length; pre[k] = v; cout << Edge[i+1].start_point << "->" << Edge[i+1].end_point << Edge[i].length << endl; } } cout << sum << endl; system("pause"); return 0; }

如有錯誤,歡迎指出。