本专栏持续输出数据结构题目集,欢迎订阅。
题目
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式:
输入数据包括城镇数目正整数 n(≤1000)和候选道路数目 m(≤3n);随后的 m 行对应 m 条道路,每行给出 3 个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从 1 到 n 编号。
输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出 −1,表示需要建设更多公路。
输入样例:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
输出样例:
12
代码
#include <stdio.h>
#include <stdlib.h>
#define MAX_EDGES 3000 // 最大边数(m ≤ 3n,n最大为1000)
// 边的结构体
typedef struct {
int u, v; // 边的两个端点
int cost; // 边的成本
} Edge;
// 比较函数,用于qsort按边的成本升序排序
int compare(const void *a, const void *b) {
return ((Edge *)a)->cost - ((Edge *)b)->cost;
}
// 并查集(Union-Find)的父节点数组
int parent[MAX_EDGES];
// 查找元素x所在集合的根节点(带路径压缩)
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]); // 路径压缩
}
return parent[x];
}
// 合并两个集合
void unionSets(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootX] = rootY;
}
}
int main() {
int n, m; // n为城镇数目,m为候选道路数目
Edge edges[MAX_EDGES]; // 存储所有边
// 读取输入
scanf("%d %d", &n, &m);
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &edges[i].u, &edges[i].v, &edges[i].cost);
}
// 按边的成本升序排序
qsort(edges, m, sizeof(Edge), compare);
// 初始化并查集,每个节点的父节点是自己
for (int i = 1; i <= n; i++) {
parent[i] = i;
}
int totalCost = 0; // 总建设成本
int edgeCount = 0; // 已选择的边数
// Kruskal算法核心:按成本从小到大选择边
for (int i = 0; i < m && edgeCount < n - 1; i++) {
int u = edges[i].u;
int v = edges[i].v;
int cost = edges[i].cost;
// 检查u和v是否属于不同集合
if (find(u) != find(v)) {
// 选择这条边
totalCost += cost;
edgeCount++;
unionSets(u, v); // 合并两个集合
}
}
// 检查是否所有节点都连通
if (edgeCount == n - 1) {
printf("%d\n", totalCost);
} else {
printf("-1\n"); // 无法连通所有节点
}
return 0;
}
1998

被折叠的 条评论
为什么被折叠?



