最小生成树的概念:在无向连通图中找到一个子图,子图的顶点个数为n(与父图一致),边的条数为n-1,且边的权重之和最小时就是最小生成树。
1. Prim算法——板子类似朴素Dijkstra算法
#include <iostream>
#include <cstring>
using namespace std;
const int N = 500 + 10, INF = 0x3f3f3f3f;
// d[i]代表点i距离圈外最近邻点的距离; 也就是点i和最近邻点的边的权重
// vis[i]代表点i是否已经出圈; vis[3]=0代表点3还没出圈,还在圈内
// 本题的边多,是稠密图,使用邻接矩阵存储无向图
int d[N], vis[N], g[N][N];
// ans存储最小生成树的边的总权重
// cnt存储最小生成树中顶点的个数
int ans, cnt;
int n, m;
void prim(int s)
{
// 将每个点到圈外最近邻点的距离初始化为无穷大
memset(d, INF, sizeof d);
d[s] = 0;
for (int i = 1; i <= n; i ++ )
{
// 找到圈内的一个点,它与圈外最近邻点的距离最小
int u = 0;
for (int j = 1; j <= n; j ++ )
if (!vis[j] && d[j] < d[u]) u = j;
// 将该圈内点出圈
vis[u] = 1;
// 生成树顶点个数加1, 生成树总边权加d[u]
if (d[u] != INF) cnt ++, ans += d[u];
// 将出圈点的邻点的d进行更新
for (int j = 1; j <= n; j ++ )
if (g[u][j] != INF && d[j] > g[u][j]) d[j] = g[u][j];
}
// 如果最小生成树中顶点个数等于图中顶点个数,则存在最小生成树,输出总权重;
if (cnt == n) cout << ans << endl;
// 如果最小生成树中顶点个数不等于图中顶点个数,则不存在最小生成树
else cout << "impossible" << endl;
}
int main()
{
cin >> n >> m;
memset(g, INF, sizeof g);
for (int i = 0; i < m; i ++ )
{
int a, b, w;
cin >> a >> b >> w;
// 无向图存两次边; 邻接矩阵存最小权重边
g[a][b] = g[b][a] = min(g[a][b], w);
}
prim(1);
return 0;
}
2. Kruskal算法——用到了并查集
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
struct Edge
{
int a, b, w;
bool operator< (const Edge &W) const
{
return w < W.w;
}
};
// p[i]代表点i的父亲; p[3]=2代表点3的父亲是2
int p[N];
Edge edges[M];
int n, m;
// ans代表最小生成树的总边权
// cnt代表最小生成树的边数, 应为n-1
int ans, cnt;
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void kruskal()
{
// 按边权升序排序图中的所有边
sort(edges, edges + m);
// 将每个点看成一个集合; 初始化并查集
for (int i = 1; i <= n; i ++ ) p[i] = i;
// 枚举每条边,如果这条边连接的两个点不在同一个集合内,就把这条边加入生成树,并合并这两点所在集合
for (int i = 0; i < m; i ++ )
{
Edge e = edges[i];
if (find(e.a) != find(e.b))
{
ans += e.w, cnt ++ ;
p[find(e.a)] = find(e.b);
}
}
// 如果最小生成树中边的个数为n-1,代表存在最小生成树; 否则不存在
if (cnt == n - 1) cout << ans << endl;
else cout << "impossible" << endl;
}
int main()
{
cin >> n >> m;
// 将所有边的两点和权重存在edges数组中
for (int i = 0; i < m; i ++ )
{
int a, b, w;
cin >> a >> b >> w;
edges[i].a = a, edges[i].b = b, edges[i].w = w;
}
kruskal();
return 0;
}