请帮我用c语言实现目标要求输入以下数据能得到期望输出:有n个城市需要建立货运路线每个城市之间的距离都已经确定你需要选择一些城市之间建立道路必须确保能够通过这些道路到达任意一个城市。现在你需要找到最小的建设成本并且保证任意两个城市之间都能通过这些道路到达。将每个城市看作图中的一个节点将每条道路看作连接两个节点的一条边边的权值即为两个节点之间的距离。然后使用最小生成树算法找到一个包含所有节点的连通子图
这里提供使用Kruskal算法的代码实现:
#include <stdio.h>
#include <stdlib.h>
#define MAX_N 100
#define MAX_M 1000
struct Edge {
int u; // 起点
int v; // 终点
int w; // 权值
};
struct Edge edges[MAX_M]; // 所有边
int parent[MAX_N]; // 并查集数组
// 比较函数,按照边权从小到大排序
int cmp(const void* a, const void* b) {
return ((struct Edge*)a)->w - ((struct Edge*)b)->w;
}
// 查找x所在的集合的代表元素
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
// 合并x和y所在的集合
void merge(int x, int y) {
parent[find(x)] = find(y);
}
// Kruskal算法求最小生成树
int kruskal(int n, int m) {
int i, ans = 0, cnt = 0;
// 初始化并查集
for (i = 0; i < n; i++) {
parent[i] = i;
}
// 对所有边按照边权从小到大排序
qsort(edges, m, sizeof(struct Edge), cmp);
// 枚举所有边
for (i = 0; i < m; i++) {
int u = edges[i].u, v = edges[i].v, w = edges[i].w;
// 如果u和v不在同一个集合中,说明加入这条边不会形成环
if (find(u) != find(v)) {
merge(u, v); // 合并u和v所在的集合
ans += w; // 将这条边的权值加入答案
cnt++; // 统计已经加入的边数
if (cnt == n - 1) { // 已经加入n-1条边,说明形成了一棵生成树
break;
}
}
}
return ans;
}
int main() {
int n, m, i;
scanf("%d%d", &n, &m);
for (i = 0; i < m; i++) {
scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w);
}
printf("%d\n", kruskal(n, m));
return 0;
}
注:如果使用Prime算法,需要使用堆(优先队列)来维护候选边集合,这里不再赘述
原文地址: https://www.cveoy.top/t/topic/eCRN 著作权归作者所有。请勿转载和采集!