圖的最小生成樹Kruskal演算法
阿新 • • 發佈:2018-11-08
克魯斯卡爾(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;
}
如有錯誤,歡迎指出。