Prim算法正确性证明
算法描述
Prim (普里姆算法): 一种基于贪心思想的求解无向图上 MST 的算法。我们直接将 Prim 算法和 Dijkstra 二者对比如下。
Dijkstra | Prim |
---|---|
贪心算法 | 贪心算法 |
顶点分为 距离已确定 和 距离未确定 顶点 | 顶点分为 距离已确定 (已加入生成树) 和 距离未确定 (未加入生成树) 顶点 |
所有顶点距离初始化为 | 所有顶点距离初始化为 |
源点 的距离初始化为 0 | 生成树起始点 的距离初始化为 0 |
以一个循环寻找 当前距离未确定顶点中距离最小者 , 立即置 的距离为「已确定」。 |
以一个循环寻找 当前距离未确定顶点中距离最小者 , 立即置 的距离为「已确定」。 |
尝试以如下方式更新 (松弛) 的邻接顶点的距离 |
尝试以如下方式更新 的邻接顶点的距离 |
结束时所有顶点最短路径及其距离被求出 | 结束时 MST 及其所有边权被求出 |
我们看到这两个算法的每一步都几乎相同,不同点主要有三处,最主要的是第 3 点。
- Prim 用于在「无向图」中求 MST,因此建图时要「双向建边」。Dijkstra 应用于有向图时单向建边,应用于无向图时双向建边。
- Dijkstra 中的「距离」指的是顶点到源点的距离。Prim 中的「距离」指的是顶点到其已在生成树上的邻接顶点 (父顶点) 的距离。
- 顶点距离更新方式不同 。
算法过程
-
建图及初始化。
- 构建双向带权图。
- 设置一个大小为 的用于标记顶点距离是否「已确定」的 数组 ,下标表示顶点。
- 设置一个大小为 的距离数组 ,下标表示顶点。初始化所有顶点的距离为 ,表示所有顶点的距离尚未确定。
- 任意选取 一个顶点作为起始顶点,置距离为 0,通常我们将第一个顶点的距离置为 0 。
-
以一个循环寻找 当前距离未确定顶点中距离最小者 ,立即置 的距离为「已确定」。
-
距离更新。尝试更新 的所有 距离未确定的 邻接顶点 的距离 。即 。
-
循环结束时,所有顶点距离被求出,也就是 MST 所有边权被求出。
正确性证明
虽然 Prim 算法过程与 Dijkstra 类似,但证明过程并不通用。如下是 Prim 算法的证明过程。
证明:在图 上执行 Prim 算法得到的生成树 是 MST。
- 记 上的 MST (之一) 是生成树 ,即证明 ,绝对值表示生成树的边权和。
- 在 生长过程中,首次 遇到的不属于 的边为 , 在此前得到的点集中, 在剩余的顶点中。从 中拿走 ,则 剩下的不连通的两部分分别为包含 的子树 以及包含 的子树 。
- 是 MST,其上必存在 到 的路径,且已知 在 中, 在 中,由于 ,则必然存在边 穿过 ,即 在 中, 在 中 (若 是 ,则 不是 ;若 是 ,则 不是 ) 。
- 当 即将被加入 时,顶点 已在 中 ( 是 当前生长到的部分)。
- 此时 是「距离未确定」的顶点。因为如果 是距离已确定的顶点,则在 中存在一条边 连接 和另一顶点,我们已经知道 是 生长过程中 首次 遇到的不属于 的边,也就是说 ,这与 矛盾,因为 一旦「距离确定」,后续就不会考察 的连边, 也就不可能加入 。
- 由于 是「距离未确定」的顶点,考察顶点 的连边时,顶点 的连边也一定会被考察。由于 在此轮考察中被 Prim 算法选入 中,而 未被选择,可知 。
- 对于 ,断开 ,则 被分成不连通的两棵子树 和 ,且 被断开,说明 与 分别在不连通的两棵子树 上。此时连上 得到的 显然是一棵生成树。因为 ,则必然有 , 否则 边权之和更小,与 是 MST 矛盾。因此 ,即 也是 MST。
- 重复上述过程,继续考察 中下一条不属于 的边,直到得到 。每一次考察,都可以得到上述 5 的结论,最终有 ,即 是 MST。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 yukiyama!
评论