朴素版prim算法
时间复杂度是 O(n^2+m), n 表示点数,m 表示边数
int n; // n表示点数
int g[N][N]; // 邻接矩阵,存储所有边
int dist[N]; // 存储其他点到当前最小生成树的距离
bool st[N]; // 存储每个点是否已经在生成树中
// 如果图不连通,则返回INF(值是0x3f3f3f3f), 否则返回最小生成树的树边权重之和
int prim()
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
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;
if (i && dist[t] == INF) return INF;
if (i) res += dist[t];
st[t] = true;
for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
}
return res;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n, m;
int g[N][N], dist[N];
bool st[N]; // 记录当前点在集合内还是集合外
int prim()
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
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;
// 不是第一个取出的节点, 并且当前节点的距离为INF, 则表示没有和集合中点相连的边。
if (i && dist[t] == INF) return INF;
// 写在前面,如果一个节点本身出现负环
// 下面这句更新后, 会影响结果, 比如g[t][j], 当t = j,更新了g[t][t], 影响res结果
// 比如4->4 -10, 更新后dist[4] = min(dist[4], g[4][4])
if (i) res += dist[t];
for (int j = 1; j <= n; j++) dist[j] = min(dist[j], g[t][j]);
st[t] = true;
}
return res;
}
int main()
{
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof g);
while (m--) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u][v] = g[v][u] = min(g[v][u], w);
}
int t = prim();
if (t == INF) puts("impossible");
else printf("%d\n", t);
return 0;
}