算法描述

Prim (普里姆算法): 一种基于贪心思想的求解无向图上 MST 的算法。我们直接将 Prim 算法和 Dijkstra 二者对比如下。

Dijkstra Prim
贪心算法 贪心算法
顶点分为 距离已确定距离未确定 顶点 顶点分为 距离已确定 (已加入生成树)距离未确定 (未加入生成树) 顶点
所有顶点距离初始化为 InfinityInfinity 所有顶点距离初始化为 InfinityInfinity
源点 ss 的距离初始化为 0 生成树起始点 ss 的距离初始化为 0
以一个循环寻找 当前距离未确定顶点中距离最小者 uu
立即置 uu 的距离为「已确定」。
以一个循环寻找 当前距离未确定顶点中距离最小者 uu
立即置 uu 的距离为「已确定」。
尝试以如下方式更新 (松弛) uu 的邻接顶点的距离
dv=min(dv,du+d(u,v))dv = min(dv, du + d(u, v))
尝试以如下方式更新 uu 的邻接顶点的距离
dv=min(dv,d(u,v))dv = min(dv, d(u,v))
whilewhile 结束时所有顶点最短路径及其距离被求出 whilewhile 结束时 MST 及其所有边权被求出

我们看到这两个算法的每一步都几乎相同,不同点主要有三处,最主要的是第 3 点。

  1. Prim 用于在「无向图」中求 MST,因此建图时要「双向建边」。Dijkstra 应用于有向图时单向建边,应用于无向图时双向建边。
  2. Dijkstra 中的「距离」指的是顶点到源点的距离。Prim 中的「距离」指的是顶点到其已在生成树上的邻接顶点 (父顶点) 的距离。
  3. 顶点距离更新方式不同

算法过程

  1. 建图及初始化。

    1. 构建双向带权图。
    2. 设置一个大小为 V|V| 的用于标记顶点距离是否「已确定」的 booleanboolean 数组 visited[]visited[] ,下标表示顶点。
    3. 设置一个大小为 V|V| 的距离数组 dists[]dists[] ,下标表示顶点。初始化所有顶点的距离为 InfinityInfinity ,表示所有顶点的距离尚未确定。
    4. 任意选取 一个顶点作为起始顶点,置距离为 0,通常我们将第一个顶点的距离置为 0 。
  2. 以一个循环寻找 当前距离未确定顶点中距离最小者 uu ,立即置 uu 的距离为「已确定」。

  3. 距离更新。尝试更新 uu 的所有 距离未确定的 邻接顶点 vv 的距离 dvdv。即 dv=min{dv,(u,v)}dv = min\{dv, |(u,v)|\}

  4. 循环结束时,所有顶点距离被求出,也就是 MST 所有边权被求出。


正确性证明

如下证明参考了 参考1 以及 参考2

虽然 Prim 算法过程与 Dijkstra 类似,但证明过程并不通用。如下是 Prim 算法的证明过程。

证明:在图 GG 上执行 Prim 算法得到的生成树 SS 是 MST。

  1. GG 上的 MST (之一) 是生成树 SminS_{min},即证明 S=Smin|S| = |S_{min}| ,绝对值表示生成树的边权和。
  2. SS 生长过程中,首次 遇到的不属于 SminS_{min} 的边为 e=(u,v)e=(u, v)uu 在此前得到的点集中,vv 在剩余的顶点中。从 SS 中拿走 ee ,则 SS 剩下的不连通的两部分分别为包含 uu 的子树 UU 以及包含 vv 的子树 VV
  3. SminS_{min} 是 MST,其上必存在 uuvv 的路径,且已知 uuUU 中,vvVV 中,由于 (u,v)Smin(u,v)∉S_{min} ,则必然存在边 f=(a,b)Sminf=(a,b)∈S_{min} 穿过 UVU → V,即 aaUU 中, bbVV 中 (若 aauu ,则 bb 不是 vv;若 bbvv,则 aa 不是 uu) 。
  4. ee 即将被加入 SS 时,顶点 aa 已在 UU 中 ( UUSS 当前生长到的部分)。
    1. 此时 aa 是「距离未确定」的顶点。因为如果 aa 是距离已确定的顶点,则在 UU 中存在一条边 gg 连接 aa 和另一顶点,我们已经知道 eeSS 生长过程中 首次 遇到的不属于 SminS_{min} 的边,也就是说 gSming∈S_{min} ,这与 fSminf∈S_{min} 矛盾,因为 aa 一旦「距离确定」,后续就不会考察 aa 的连边,ff 也就不可能加入 SminS_{min}
    2. 由于 aa 是「距离未确定」的顶点,考察顶点 uu 的连边时,顶点 aa 的连边也一定会被考察。由于 ee 在此轮考察中被 Prim 算法选入 SS 中,而 ff 未被选择,可知 ef|e|≤|f|
  5. 对于 SminS_{min} ,断开 f=(a,b)f=(a,b) ,则 SminS_{min} 被分成不连通的两棵子树 AABB,且 uabvu → a → b → v 被断开,说明 uuvv 分别在不连通的两棵子树 A,BA, B 上。此时连上 e=(u,v)e=(u,v) 得到的 SAeBS_{AeB} 显然是一棵生成树。因为 ef|e|≤|f| ,则必然有 e=f|e|=|f| , 否则 SAeBS_{AeB} 边权之和更小,与 SminS_{min} 是 MST 矛盾。因此 SAeB=Smin|S_{AeB}|=|S_{min}|,即 SAeBS_{AeB} 也是 MST。
  6. 重复上述过程,继续考察 SS 中下一条不属于 SminS_{min} 的边,直到得到 SS 。每一次考察,都可以得到上述 5 的结论,最终有 S=Smin|S|=|S_{min}|,即 SS 是 MST。

image.png