最小生成树 (Minimum Spanning Tree)
最小生成树问题是拟阵 (Matroid) 理论在图论中的直观应用。本章不仅涵盖经典的 Kruskal 与 Prim 算法,更深入探讨连通性的一致性证明、Kruskal 重构树的瓶颈映射,以及有向图下的朱-刘算法。
一、 核心理论与连通性证明
MST 的正确性建立在两个核心性质之上:切分定理 (Cut Property) 和 回路定理 (Cycle Property)。
1. 切分定理与贪心选择
2. 连通性一致性校验 (Connectivity Invariant)
在 Kruskal 算法中,我们通过并查集 (DSU) 维护连通性。
- 不变性:在任意时刻,已选边集构成的每个连通分量本身都是其所含顶点集的 MST。
- 最终状态:当选择了 条边且无环时,由树的性质知图必连通。
二、 进阶结构:Kruskal 重构树
Kruskal 重构树 (ExKruskal Tree) 是处理瓶颈路径问题的利器。
1. 构造过程
在执行 Kruskal 时,若要合并两个集合 :
- 新建一个节点 ,点权 。
- 将 所在集合的根节点分别作为 的左右儿子。
- 成为新集合的根。
2. 性质推导
- 堆性质:重构树是一个大根堆(对于最小生成树)。
- 瓶颈映射:原图中 之间所有路径中最大边权的最小值,等于重构树上 的点权。
- 可达性范围:从 出发只经过权值 的边能到达的点集,是重构树中 的某个祖先 ( 且 ) 的子树中的所有叶子节点。
三、 有向最小生成树:朱-刘算法
1. 核心思想:环路缩减 (Cycle Contraction)
有向 MST(树形图)不能直接用贪心,因为入边选择受根节点制约。
- 收敛分析:每次缩环都会减少至少一个节点,最多执行 次,总复杂度 。
四、 工业级 C++ 实现 (Kruskal 重构树)
/**
* @brief Kruskal 重构树构造
* val[node] 存储边权,1~n 为叶子,n+1~2n-1 为辅助点
*/
void build_ex_kruskal() {
sort(edges.begin(), edges.end());
int cur_idx = n; // 新节点索引
for (auto& e : edges) {
int fu = find(e.u), fv = find(e.v);
if (fu != fv) {
cur_idx++;
val[cur_idx] = e.w;
fa[fu] = fa[fv] = cur_idx;
adj[cur_idx].push_back(fu);
adj[cur_idx].push_back(fv);
if (--components == 1) break;
}
}
}
五、 精选练习与解析
练习 1:次小生成树 (Second Best MST)
求权值之和严格大于 MST 且最小的生成树。
Check Solution
解析:
- 首先求出 MST。
- 遍历所有非树边 。
- 替换 MST 中 路径上的最大边 。
- 若 ,则 是一个候选值。
- 若 ,则需替换路径上的严格次大边。
练习 2:瓶颈生成树
求一棵生成树,使其最大边权最小。
Check Solution
解析: 定理:任何一棵最小生成树都是瓶颈生成树。反之不一定成立。 直接运行 Kruskal 算法,最后一笔加入的边权即为最小瓶颈。
练习 3:生成树计数 (Matrix Tree Theorem)
给定无向图,求生成树的总数。
Check Solution
解析:
- Kirchhoff 矩阵 。
- :度数矩阵(对角线为点度数)。
- :邻接矩阵。
- 定理: 的任意一个 阶主余子式的行列式值即为生成树数量。
- 计算:高斯消元求行列式,复杂度 。
练习 4:边带限制的 MST - 最小度限制生成树
求一棵生成树,使得根节点 的度数恰好为 ,且总权值最小。
Check Solution
解析:
- 去掉 后,图分为若干连通块。每个连通块至少连一条边到 以保证连通。
- 假设连通块数为 。若 ,无解。
- 先构造 度限制 MST。
- 逐步增加度数至 :每次找一条边 替换掉形成的环中的非 关联最大边,使得权值增量最小。