最小生成樹prim演算法與kruskal演算法
阿新 • • 發佈:2019-01-29
最小生成樹:在連通網的所有生成樹中,所有邊的代價和最小的生成樹,稱為最小生成樹。
分析:從一個初始點開始,每次獲取與該點直連的點,並與之前獲取的可連線的邊比較,得到最小邊,然後將連線的點併入集合(以後的點不能在包括他,要不然會形成迴路),直到遍歷完所有頂點糾結束。
程式碼:
#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;
}