并查集、MST 与离线激活 · HTML
数学 / 逻辑形态
图 G=(V,E),边权可比较;求含 |V|-1 条边的生成树 T,使边权总和最小。
识别信号
- 连接全部点并最小化总成本
- 可从候选边自由挑选
- 无向边带可排序代价
- 选边时只需判断是否跨组件
- 也可能询问节省成本或瓶颈连接
容易误判的相似信号
| Signal | Why it is different |
|---|
| 单源最短路 | MST 最小化整棵树总边权,不保证源到各点路径最短。 |
| 有向最小连接 | 普通 Kruskal 面向无向图;有向生成结构使用不同算法。 |
核心不变量
扫描到当前权重时,已选森林可扩展成某棵 MST;只接受跨越不同组件的最轻边。
状态、转移与处理顺序
| Item | Definition |
|---|
| State | 排序边列表、表示森林的 DSU、累计权重 total、已选边 chosen。 |
| Transition | 按权重非降序取边;union 成功则选择并累加,失败表示会成环。 |
| Frontier / order | 尚未扫描边按权重有序;当前最轻跨组件边是 cut property 保证的安全边。 |
Python 骨架
def kruskal(n, edges):
p, sz = list(range(n)), [1] * n
def find(x):
while x != p[x]:
p[x] = p[p[x]]; x = p[x]
return x
def union(a, b):
a, b = find(a), find(b)
if a == b: return False
if sz[a] < sz[b]: a, b = b, a
p[b] = a; sz[a] += sz[b]
return True
total, chosen = 0, []
for w, u, v in sorted(edges):
if union(u, v):
total += w; chosen.append((u, v, w))
if len(chosen) == n - 1: break
return (total, chosen) if len(chosen) == n - 1 else None
正确性思路
- cut property 保证跨任一当前割的最轻边属于某棵 MST。
- 排序保证接受边不重于尚未处理的替代边。
- DSU 拒绝组件内部边,所以森林始终无环。
- 连通时选满 n-1 条安全边,形成最小生成树。
复杂度
| Time | Space | Parameters |
|---|
| O(E log E),排序主导 | O(V+E) | V 为顶点数,E 为边数;DSU 部分 O(E α(V)) |
边界条件
- 不连通时不存在完整 MST
- 平行边可自然竞争
- 自环总被拒绝
- 负边权不影响正确性
- 单顶点的答案为 0
错误模式
| Pattern | Why it fails / fix |
|---|
| 排序字段放错 | 若边存成 (u,v,w),必须显式按 w 排序。 |
| 未在 V-1 条边停止 | 树已完成后继续扫描没有价值。 |
| 漏查连通性 | 少于 V-1 条边时累计值只是森林,不是完整答案。 |
选择与排除规则
- 边列表天然给出:Kruskal 通常最直接。
- 稠密邻接矩阵:可比较 Prim。
- 目标是源到终点:先辨别 shortest path,不套 MST。
- 阈值连通查询:考虑同排序骨架的 offline DSU。
相关模板
原创微型例子
| 环节 | 内容 |
|---|
| Result | 依次选 1、2、3,总成本 6。 |
| Scenario | 四站点候选边权为 2、1、3、8、5。 |
| Walkthrough | 前三条安全边已连通四点;昂贵边无需再看。 |
Recall prompts
我的补充