| 项目 | 值 |
|---|---|
| 主题 | 最小生成树(MST) |
| 核心概念 | 连通图的极小连通子图,含所有顶点,仅 $n-1$ 条边,且边权之和最小 |
| 时间复杂度 | $O(|E|)$、$O(|E|\log|E|)$、$O(|V|^2)$ |
| 难度 | ⭐⭐⭐ |
| 重要性 | ⭐⭐⭐⭐⭐ |
从某个顶点开始,每次选择与当前树相连的最小权边,将新顶点加入树中。
void Prim(MGraph G, int v0) {
int lowcost[MaxVertexNum]; // 到生成树的最小距离
int adjvex[MaxVertexNum]; // 最小边的另一端
for (int i = 0; i < G.vexnum; i++) {
lowcost[i] = G.edge[v0][i];
adjvex[i] = v0;
}
lowcost[v0] = 0;
for (int i = 1; i < G.vexnum; i++) {
int min = INF, k = -1;
for (int j = 0; j < G.vexnum; j++)
if (lowcost[j] != 0 && lowcost[j] < min) { min = lowcost[j]; k = j; }
printf("(%d, %d)\n", adjvex[k], k);
lowcost[k] = 0;
for (int j = 0; j < G.vexnum; j++)
if (G.edge[k][j] < lowcost[j]) { lowcost[j] = G.edge[k][j]; adjvex[j] = k; }
}
}
时间复杂度 $O(|V|^2)$,适合稠密图。
每次选择权值最小且不构成环的边加入生成树。
typedef struct { int u, v, w; } Edge;
void Kruskal(Edge edges[], int n, int e) {
Sort(edges, e); // 按权值排序
int UFSets[MaxSize]; Init(UFSets, n);
int count = 0;
for (int i = 0; i < e && count < n-1; i++) {
int u = edges[i].u, v = edges[i].v;
if (Find(UFSets, u) != Find(UFSets, v)) {
printf("(%d, %d)\n", u, v);
Union(UFSets, u, v);
count++;
}
}
}
时间复杂度 $O(|E|\log|E|)$(主要取决于排序),适合稀疏图。
| 特性 | Prim | Kruskal |
|---|---|---|
| 策略 | 从顶点扩展 | 从边选择 |
| 时间 | $O(|V|^2)$ | $O(|E|\log|E|)$ |
| 适用 | 稠密图 | 稀疏图 |
| 实现 | 类似 Dijkstra | 需要并查集 |
| 步骤 | 选边 | lowcost 更新 |
|---|---|---|
| 初始化 | — | $[0, 6, 5, 1, \infty]$ |
| 1 | (A,D)=1 | $[0, 6, 4, 0, 5]$ |
| 2 | (D,C)=4 | $[0, 3, 0, 0, 5]$ |
| 3 | (C,B)=3 | $[0, 0, 0, 0, 2]$ |
| 4 | (B,E)=2 | $[0, 0, 0, 0, 0]$ |
MST 边:(A,D)=1, (D,C)=4, (C,B)=3, (B,E)=2,总权值 10。
边按权排序:(A,D)=1, (B,E)=2, (B,C)=3, (C,D)=4, (A,C)=5, (D,E)=5, (A,B)=6, (C,E)=6。
依次选 (A,D)、(B,E)、(B,C)、(C,D),已 4 条边($n=5$)停止。总权值 10。
| 算法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| Prim | $O(|V|^2)$ | $O(|V|)$ | 稠密图 |
| Kruskal | $O(|E|\log|E|)$ | $O(|E|)$ | 稀疏图 |
↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。