最小生成树的唯一性判定(Uniqueness of Minimum Spanning Tree)
题目描述
给定一个无向连通图 G=(V, E),每条边 e 有一个正的实数边权 w(e)。我们需要判断这个图的最小生成树(Minimum Spanning Tree, MST)是否唯一。换句话说,是否存在两棵不同的生成树 T1 和 T2,它们具有相同的最小总权值,并且这个总权值严格小于其他所有生成树的权值。
直观理解
在最小生成树算法中(如 Kruskal 或 Prim),我们通常会得到一棵最小生成树。但如果图中存在多条边权相同的边,或者存在其他具有相同总权值的生成树,那么最小生成树可能不唯一。我们需要设计一个算法来判断是否唯一。
核心思路
判断最小生成树唯一性的关键思想是:先求出任意一棵最小生成树 T,然后检查是否存在另一棵生成树 T',其总权值与 T 相同,但包含的边集不同。这可以通过检查 T 中每条边,看能否用另一条等权或更优的边替换而不改变总权值来实现。常见的方法是:
- 先使用标准算法(如 Kruskal 或 Prim)求出一棵 MST,记为 T。
- 对 T 中的每条边 e,检查是否存在另一条不在 T 中的边 e',满足 w(e') = w(e) 且将 e' 加入 T 会形成一个包含 e 的环,且 e 是这个环上权值最大的边(即 e 可被等权边替换)。
- 如果存在这样的 e,则 MST 不唯一。
下面我们一步步深入细节。
步骤 1:求一棵最小生成树
首先,我们使用 Kruskal 算法(或 Prim 算法)求出一棵最小生成树 T。
- Kruskal 算法:将边按权值从小到大排序,依次考虑每条边,如果加入该边不会形成环,就将其加入 MST,直到选出 n-1 条边(n 为顶点数)。
- 在排序时,如果有多条边权值相同,可以按任意顺序处理,但我们需要记录最终选入 MST 的边集 T。
- 时间复杂度:O(m log m),其中 m 是边数。
步骤 2:理解替换边的条件
考虑 MST 的一条边 e ∈ T。如果我们将 e 从 T 中移除,那么 T 会被分成两个连通分量 A 和 B。根据 MST 的切割性质,所有连接 A 和 B 的边中,e 是权值最小的边之一(可能有多条边权值相同且最小)。
如果存在另一条边 e'(e' ∉ T)也连接 A 和 B,且 w(e') = w(e),那么我们可以用 e' 替换 e,得到另一棵生成树 T' = (T \ {e}) ∪ {e'},其总权值相同。
因此,判断唯一性的问题转化为:对 T 中的每条边 e,检查连接其对应两个连通分量的边中,是否存在另一条与 e 权值相等的边。
步骤 3:高效判断替换边的存在
暴力方法:对 T 中每条边 e,删除 e 后,遍历所有非树边 e',检查是否连接两个连通分量且权值等于 w(e)。这需要 O(m) 时间检查每条边,总时间 O(nm)(n-1 条树边),比较慢。
更优的方法:
- 对每条非树边 e' = (u, v),其权值为 w(e')。考虑在 MST T 中,u 到 v 的唯一路径 P。路径 P 上的最大边权记为 max_weight(u, v)。
- 如果 w(e') = max_weight(u, v),说明路径 P 上存在一条边 e 权值等于 w(e'),那么 e 可以被 e' 替换,从而得到另一棵 MST。
- 因此,我们只需检查所有非树边 e',看是否存在 w(e') = max_weight(u, v)。如果存在,则 MST 不唯一。
注意:如果 w(e') < max_weight(u, v),那么 T 不是 MST,矛盾。所以只需检查相等的情况。
步骤 4:计算路径最大边权
我们需要对每对顶点 (u, v) 计算在 T 中路径上的最大边权。由于 T 是树,我们可以用以下方法:
- 对每个顶点作为根,做一次 DFS 或 BFS,记录从根到每个点的路径上的最大边权。但这样需要 O(n^2) 时间,当 n 很大时可能较慢。
- 更高效的做法:利用最近公共祖先(LCA)与倍增法。预处理每个节点的 2^k 级祖先,以及从该节点到祖先路径上的最大边权。这样可以在 O(log n) 时间内查询任意两点路径上的最大边权。
- 具体预处理:
- 设 up[u][k] 为节点 u 的 2^k 级祖先,max_edge[u][k] 为从 u 到 up[u][k] 路径上的最大边权。
- 初始化 up[u][0] 为 u 的父节点,max_edge[u][0] 为 u 与父节点之间的边权。
- 递推:up[u][k] = up[ up[u][k-1] ][k-1],max_edge[u][k] = max(max_edge[u][k-1], max_edge[ up[u][k-1] ][k-1])。
- 查询路径 (u, v) 上的最大边权:先找到 LCA(u, v),然后分别查询 u 到 LCA 和 v 到 LCA 路径上的最大边权,再取两者最大值。
步骤 5:算法流程
- 使用 Kruskal 算法求出 MST T,并记录树边集合。
- 以 T 为树,任选一个根(如节点 1),进行 DFS 或 BFS 构建 parent 数组和深度数组,同时记录每条树边的权值。
- 使用倍增法预处理 up 和 max_edge 数组(O(n log n))。
- 遍历每条非树边 e' = (u, v, w):
- 计算 T 中 u 到 v 路径上的最大边权 max_w。
- 如果 max_w == w,则说明 MST 不唯一,算法结束。
- 如果所有非树边检查后都没有出现 max_w == w,则 MST 唯一。
步骤 6:复杂度分析
- 求 MST:O(m log m)。
- 预处理 LCA 与最大边权:O(n log n)。
- 检查非树边:每条边 O(log n),共 O(m log n)。
总时间复杂度:O(m log m + (n+m) log n),通常可视为 O(m log n)(因为 m ≥ n-1)。
步骤 7:边界情况与注意事项
- 如果图不连通,则没有生成树,题目通常保证连通。
- 如果有多条边权值相同,Kruskal 处理时可能选择任意一条,这不会影响判断结果,因为我们的检查覆盖了所有非树边。
- 如果存在非树边 e' 的权值小于路径上的最大边权,这不可能发生,因为那样的话 T 不是 MST,与步骤 1 矛盾。
- 实际实现时,可以边求 MST 边记录被丢弃的边(非树边),然后只检查这些非树边即可。
总结
判断最小生成树唯一性的高效算法:先求一棵 MST,再利用树上路径最大边权查询检查是否存在可替换的非树边。这个算法结合了经典 MST 算法、LCA 与倍增技巧,是图论中一个有趣的应用。