题目描述
某地要建设 5G 网络,共有 N 个基站(编号 1~N),以及 V 条候选光缆线路。第 i 条线路连接基站 A 和 B,建设成本为 C。要求修建若干条线路使得所有基站互相连通 ,求最小总建设成本;若无论如何都无法连通,输出 -1。
数据范围: 1 ≤ N ≤ 1000,1 ≤ V ≤ N*(N-1)/2,1 ≤ C ≤ 10⁴。
示例
输入:
3 3
1 2 3
1 3 1
2 3 5
输出:
4
说明:选择 1-3(成本1)和 1-2(成本3),总成本 4 最小。
思路
最小生成树经典题,用 Kruskal 算法 + 并查集:
- 把所有边按成本从小到大排序;
- 依次考察每条边:若两端点不在同一集合(用并查集判断),选它并合并集合;
- 选满
N-1条边即得最小总成本;扫完边数不足N-1,说明图不连通,输出-1。
C 代码
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int u, v, w;
} Edge;
int cmpEdge(const void *a, const void *b)
{
const Edge *ea = (const Edge *)a;
const Edge *eb = (const Edge *)b;
return ea->w - eb->w;
}
#define MAXN 1005
int fa[MAXN]; /* 并查集父节点 */
int find(int x)
{
if (fa[x] != x) fa[x] = find(fa[x]); /* 路径压缩 */
return fa[x];
}
int main(void)
{
int n, m;
if (scanf("%d %d", &n, &m) != 2) return 0;
Edge *e = (Edge *)malloc(m * sizeof(Edge));
for (int i = 0; i < m; i++)
scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
/* 1. 按成本升序排序 */
qsort(e, m, sizeof(Edge), cmpEdge);
/* 2. 初始化并查集 */
for (int i = 1; i <= n; i++) fa[i] = i;
/* 3. 贪心选边 */
long long total = 0;
int used = 0; /* 已选边数 */
for (int i = 0; i < m && used < n - 1; i++) {
int ru = find(e[i].u), rv = find(e[i].v);
if (ru == rv) continue; /* 两端已连通,选它会成环 */
fa[ru] = rv;
total += e[i].w;
used++;
}
if (used == n - 1) printf("%lld\n", total);
else printf("-1\n"); /* 图不连通 */
free(e);
return 0;
}