生成最小树是指在一个无向连通图上选择适当的边,生成一个子连通图满足全部边的权重加起来最小的条件
应用:给出n个城市和各个城市间的距离,问若要修建若干个公路连通所有城市,问应该如何修建和这时的公路长度。。。
以下是经 黑车司机 总结和优化的最小树算法
用到的数据结构
1.node_set[i] ,节点i所属的集合,刚开始是i
2.size[i],集合i包含的节点,刚开始是1
3.edge[i], edge结构保存无向边的信息,包括两边的节点和边的权重
大概流程:
1.初始化数据结构
2.对edge数组进行升序排序
3.遍历edge数组,如果edge[i]两边的节点来自不同的集合,则将这连个结合合并起来,
直至全部节点都属于同一个集合。
代码和注释:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 100;
int node_set[maxn]; //the set node i belong to
int size[maxn]; //the munber of element that in set i
vector<int> ans; //save the edge that take accepted
struct Edge{
int node1;
int node2;
int val;
}edge[maxn];
void init(int n){
for (int i = 0; i < n; i++){
size[i] = 1;
node_set[i] = i;
}
return;
}
int finds(int n){ //find the set node[n] belong to
return(node_set[n] == n ? n : node_set[n] = finds(node_set[n]));
}
void show(){
for (auto t : ans)
printf("%d ----- %d ( %d )\n", edge[t].node1, edge[t].node2, edge[t].val);
}
void connect(int a, int b){ //connect node a and node b, use it after make sure a and d come from different set
int as = finds(a);
int bs = finds(b);
if (size[as] <= size[bs]){
node_set[as] = bs;
size[bs]++;
}
else{
node_set[bs] = as;
size[as]++;
}
return;
}
int kruskal(int n){ //input the total munber of node return mini length conect all the node
init(n);
int len = 0;
for (int i = 0; i < n; i++){
if (finds(edge[i].node1) != finds(edge[i].node2)){
connect(edge[i].node1, edge[i].node2);
ans.push_back(i);
len += edge[i].val;
}
}
show();
return len;
}
int main(){
int n, m; //munber of node and dege
cin >> n >> m;
for (int i = 0; i < m; i++) cin >> edge[i].node1 >> edge[i].node2 >> edge[i].val;
sort(edge, edge + m, [](Edge &a, Edge &b){return a.val < b.val; });
cout <<"total length of mini stree is :" << kruskal(n) << endl;
}
/*
数据用例
6 10
1 2 22
0 1 8
0 2 12
0 3 15
0 4 30
0 5 7
1 5 9
2 3 6
3 4 2
4 5 31
*/
运行结果和分析: