最小生成树唯一性判定算法
题目描述
给定一个无向连通加权图 G = (V, E, w),其中 w(e) 表示边 e 的权重。我们已经知道至少存在一棵最小生成树(MST)。请设计一个算法,判定这个图的最小生成树是否唯一。换句话说,是否存在另一棵不同的生成树 T',满足 w(T') = w(T),其中 T 是某一棵最小生成树?
解题过程讲解
第一步:理解问题的本质
首先,我们需要明确什么情况下最小生成树是唯一的。回顾最小生成树的性质(以 Kruskal 或 Prim 算法为例):
- 如果图中所有边的权重都互不相同,那么 MST 一定是唯一的。
- 但如果存在权重相等的边,就可能出现多棵总权重相同的生成树。
关键在于:在构造 MST 时,当我们在某个步骤面临多条权重相同的边可以选择,不同的选择可能导致不同的生成树结构,但最终总权重相同。
因此,判定唯一性就转化为:检查是否可以在保持最小总权重的条件下,用另一条边替换 MST 中的某条边。
第二步:核心思路——替换边法
一个经典判定方法是:
- 先求出任意一棵最小生成树 T(例如用 Kruskal 或 Prim 算法)。
- 对 T 中的每一条边 e ∈ T,尝试用一条不在 T 中且权重与 e 相同的边 e' 替换 e,并检查替换后是否仍然是一棵生成树,且总权重不变。
- 如果存在这样一条可替换的边,则 MST 不唯一;否则唯一。
为什么这个思路是正确的?
- 如果存在另一棵 MST T' ≠ T,且 w(T') = w(T),那么 T 和 T' 的边集至少有一条边不同。
- 考虑 T 中的某条边 e 不在 T' 中。由于 T' 也是一棵生成树,将 e 加入 T' 会形成一个环 C,且 C 上一定存在另一条边 e' ∈ T' 但 e' ∉ T。
- 由切性质(cut property)可知,e 和 e' 的权重相等,且 e' 是连接 e 对应的某个割的另一条最小权重边。
- 因此,在 T 中尝试用 e' 替换 e 是可行的,且权重不变。
第三步:算法步骤细化
步骤 1:求任意一棵 MST T
使用 Kruskal 或 Prim 算法,得到 T 和它的总权重 W。
记录 T 中的边集,以及每条边的端点。
步骤 2:枚举 T 中的每一条边 e = (u, v)
- 从原图 G 中暂时移除边 e(或标记为不可用)。
- 在移除 e 后的图上,重新运行 MST 算法(如 Kruskal),但只考虑权重 ≤ w(e) 的边(因为如果使用权重更大的边,总权重会增加,不可能与 W 相等)。
- 在构建新生成树的过程中,如果能够找到一棵总权重等于 W 的生成树,则说明存在另一棵 MST(它不包含 e 但总权重相同),于是判定不唯一。
- 如果找不到,则继续测试下一条边。
步骤 3:判断
如果所有边 e 都测试完都没有找到替换,则 MST 唯一。
第四步:优化与高效实现
上述暴力方法需要对每条 T 边跑一次 MST 算法,最坏复杂度 O(E log E) 每条边,总共 O(VE log E),比较慢。
我们可以优化:
方法 A:利用最小瓶颈路思想
- 对每条非树边 e' = (u, v) ∉ T,考虑它加入 T 后形成的环。
- 在环上找到权重最大的边(即瓶颈边)。如果这个最大边的权重等于 e' 的权重,那么就可以用 e' 替换那条最大边,从而得到另一棵总权重相同的生成树。
- 因此,算法变为:
- 求 MST T。
- 预处理 T 上任意两点间路径上的最大边权重(可以用树上倍增或树链剖分在 O(n log n) 时间内预处理,O(log n) 查询)。
- 对每条非树边 e' = (u, v) 权重 w',查询 T 中 u 到 v 路径上的最大边权重 w_max。
- 如果 w_max == w',说明可以替换,MST 不唯一。
方法 B:利用边的分类
- 将边按权重分组。
- 对每个权重值,先考虑所有该权重的边,用 Kruskal 算法构建 MST 时,记录哪些该权重的边被选中(成为 MST 边),哪些被丢弃(因为两端已在同一连通分量)。
- 关键:如果在处理某个权重的边时,存在一条边 e' 被丢弃,但它在加入时连接的两个连通分量之间,在该权重下还有另一条边 e(树边)连接相同的两个连通分量,那么 e' 就可以替代 e,得到另一棵 MST。
- 实现时可以用并查集,按权重从小到大处理,对每个权重,先收集所有该权重的边,然后依次尝试加入,如果某条边加入时两端已经连通,则标记它是一条“可替代”的边;接着正式加入该权重中被选为 MST 的边到并查集。如果在某个权重中发现了“可替代”边,则 MST 不唯一。
第五步:算法实现示例(采用方法 A)
输入:图 G = (V, E, w)
输出:True(如果 MST 唯一),False(如果不唯一)
1. 用 Kruskal 算法求出 MST T,得到边集 T_edges。
2. 构建 T 的邻接表表示(因为 T 是树,有 V-1 条边)。
3. 预处理 T 上任意两点间路径的最大边权重:
- 以任意节点为根,做 DFS 或 BFS 得到父节点、深度。
- 用倍增法(binary lifting)存储每个节点向上 2^k 步的祖先,以及到该祖先路径上的最大边权重。
4. 对每条非树边 e' = (u, v, w'):
a. 在 T 上查询 u 到 v 路径上的最大边权重 w_max。
b. 如果 w_max == w',则返回 False(不唯一)。
5. 如果所有非树边都检查完,没有发现 w_max == w' 的情况,返回 True(唯一)。
预处理 O(V log V),查询 O(log V) 每条非树边,总复杂度 O(E log V)。
第六步:举例说明
考虑一个正方形加一条对角线的图,四个顶点 A,B,C,D,边:
AB=1, BC=2, CD=1, DA=2, AC=2(对角线)。
- 用 Kruskal 选边:先选 AB(1), CD(1), 然后可以从 BC(2), DA(2), AC(2) 中选两条。
- 一种 MST 是 {AB, CD, BC, DA} 权重 1+1+2+2=6。
- 检查非树边 AC(2):在 MST 中 A 到 C 路径是 A-B-C,最大边权重是 max(1,2)=2,等于 AC 的权重 2,因此可以用 AC 替换 BC(或替换 DA,但替换后结构不同),得到另一棵 MST {AB, CD, AC, DA},权重 6。
所以 MST 不唯一。
总结
最小生成树唯一性判定可通过检查是否存在另一条与某 MST 边权重相同的非树边,能替换它而保持总权重不变来实现。高效算法利用树上路径最大边权查询,可在 O(E log V) 时间内判定。