题解:AcWing 858 Prim算法求最小生成树
【题目来源】
AcWing:858. Prim算法求最小生成树 - AcWing题库
【题目描述】
给定一个 \(n\) 个点 \(m\) 条边的无向图,图中可能存在重边和自环,边权可能为负数。
求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible。
给定一张边带权的无向图 \(G=(V,E)\),其中 \(V\) 表示图中点的集合,\(E\) 表示图中边的集合,\(n=|V|\),\(m=|E|\)。
由 \(V\) 中的全部 \(n\) 个顶点和 \(E\) 中 \(n-1\) 条边构成的无向连通子图被称为 \(G\) 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 \(G\) 的最小生成树。
【输入】
第一行包含两个整数 \(n\) 和 \(m\)。
接下来 \(m\) 行,每行包含三个整数 \(u,v,w\),表示点 \(u\) 和点 \(v\) 之间存在一条权值为 \(w\) 的边。
【输出】
共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible。
【输入样例】
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
【输出样例】
6
【解题思路】

【算法标签】
《AcWing 858 Prim算法求最小生成树》 #最小生成树# #Prim#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 510; // 最大节点数
const int INF = 0x3f3f3f3f; // 无穷大值
int n; // 节点数量
int m; // 边数量
int g[N][N]; // 邻接矩阵存储图
int dist[N]; // 存储当前生成树到各节点的最小距离
bool st[N]; // 标记节点是否已加入最小生成树
/**
* Prim算法:求解无向连通图的最小生成树
* @return 最小生成树的总权重,INF表示图不连通
*/
int prim()
{
// 初始化距离数组为无穷大
memset(dist, 0x3f, sizeof(dist));
int res = 0; // 存储最小生成树的总权重
// 循环n次,每次加入一个节点到生成树
for (int i = 0; i < n; i++)
{
int t = -1; // 用于记录当前距离最小的节点
// 在所有未加入生成树的节点中,找到距离最小的节点
for (int j = 1; j <= n; j++)
{
if (!st[j] && (t == -1 || dist[t] > dist[j]))
{
t = j;
}
}
// 如果不是第一个节点(i>0)且最小距离为无穷大,说明图不连通
if (i && dist[t] == INF)
{
return INF; // 图不连通,无法生成最小生成树
}
// 如果不是第一个节点,将当前边的权重加入总结果
if (i)
{
res += dist[t];
}
// 用新加入的节点t更新其他节点到生成树的最小距离
for (int j = 1; j <= n; j++)
{
dist[j] = min(dist[j], g[t][j]);
}
// 标记节点t已加入最小生成树
st[t] = true;
}
return res;
}
int main()
{
// 输入节点数和边数
scanf("%d%d", &n, &m);
// 初始化邻接矩阵为无穷大(表示不可达)
memset(g, 0x3f, sizeof(g));
// 输入所有边的信息
while (m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
// 无向图,双向设置权重,并处理重边(取最小值)
g[a][b] = g[b][a] = min(g[a][b], c);
}
// 调用Prim算法计算最小生成树
int t = prim();
// 输出结果
if (t == INF)
{
// 图不连通,无法生成最小生成树
puts("impossible");
}
else
{
// 输出最小生成树的总权重
printf("%d\n", t);
}
return 0;
}
【运行结果】
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
6
浙公网安备 33010602011771号