最小生成树问题的贪心算法还可以采用最短边策略:设最小生成树的边集为TE,最短边策略从TE={}开始,每一次贪心选择都是在边集E中选取最短边(u,v),如果边(u,v)加入集合TE不产生回路,则将边(u,v)加入边集TE。Kruskal算法就应用了这个贪心策略,使生成树以一种随意的方式生长,先让森林中的树木随意生长,每生长一次就将两棵树合并,最后合并成一棵树。请设计C++语言的Kruskal算法并上机实现。
时间: 2023-06-13 07:08:50 浏览: 114
以下是C++语言的Kruskal算法实现,假设图的边集已经保存在一个数组edges中,每条边包含起点、终点和边权值:
```c++
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1005; // 最大顶点数
const int MAXM = 10005; // 最大边数
struct Edge {
int u, v, w; // 起点、终点和边权值
} edges[MAXM];
int father[MAXN]; // 并查集数组,用于判断是否产生回路
int find(int x) { // 查找x所在集合的根节点
if (father[x] == x) {
return x;
}
return father[x] = find(father[x]); // 路径压缩
}
void Union(int x, int y) { // 将x所在集合和y所在集合合并
father[find(x)] = find(y);
}
bool cmp(Edge a, Edge b) { // 边按照权值从小到大排序
return a.w < b.w;
}
void Kruskal(int n, int m) { // n表示顶点数,m表示边数
for (int i = 1; i <= n; i++) {
father[i] = i; // 初始化并查集数组
}
sort(edges, edges + m, cmp); // 排序
int cnt = 0, ans = 0; // cnt表示已选取的边数,ans表示最小生成树的边权和
for (int i = 0; i < m; i++) {
int u = edges[i].u, v = edges[i].v, w = edges[i].w;
if (find(u) != find(v)) { // 如果加入该边不产生回路
Union(u, v); // 合并两个集合
ans += w; // 累加边权
cnt++; // 边数加1
if (cnt == n - 1) { // 边数达到n-1,即为最小生成树
break;
}
}
}
cout << "最小生成树的边权和为:" << ans << endl;
}
int main() {
int n, m;
cout << "请输入顶点数和边数:" << endl;
cin >> n >> m;
cout << "请输入每条边的起点、终点和边权值:" << endl;
for (int i = 0; i < m; i++) {
cin >> edges[i].u >> edges[i].v >> edges[i].w;
}
Kruskal(n, m);
return 0;
}
```
该算法的时间复杂度为O(mlogm),其中m为边数。
阅读全文