Prim正确性的证明

P r i m Prim Prim的过程

此处以最小生成树为例。最大生成树,其实也是可以使用 p r i m prim prim 的。 P r i m Prim Prim 的过程是:

首先,任意选择一个点,作为一个连通块。接下来,重复执行下面的步骤,直到所有点都被加入了连通块中:

  1. 定义两个点之间的距离,为两个点之间的最短路。
  2. 定义一个点 x x x 到当前连通块 S S S 的距离,为 min ⁡ v ∈ S d i s ( x , v ) \min_{v\in S}dis(x,v) minvSdis(x,v) 。即 x x x 到达 S S S 中的某个点的距离,取最小值。
  3. 找到一个点,这个点到当前连通块的距离最小。
  4. 将这个点加入连通块,并且加入它的距离所对应的边。

有一个特点,就是新加入的点一定与当前联通块中的某个点直接相邻。

正确性证明

利用一种反证法。我们假设某一步搞错了,看看接下来会发生什么。

这里的“出错”,我们定义成:加入了一条错误的边(它本不属于最小生成树,但程序误认为其应当属于)。

最初:绝对正确

无论怎么说,只选择了一个点的时候是一定正确的——此时一条边也没有,怎么会有搞错的边呢?

中途:万一错了

假设某一次加边,加错了!在此之前,我们所加入的边都是正确的。

不妨设原本正确的连通块是 T 0 T_0 T0 ,此时加入了一条出错的边 ( u , v ) (u,v) (u,v) ,那么整个程序结束后应该长这样:
Prim正确性的证明_第1张图片
生成树包含每一个点,所以 T 0 + T 1 = V T_0+T_1=V T0+T1=V 。此处的 V V V 指的是所有的点。

正确的生成树是什么呢?应该是

Prim正确性的证明_第2张图片
T 0 , T 1 T_0,T_1 T0,T1 仍然是那两个 T 0 , T 1 T_0,T_1 T0,T1 ,没有发生变化。

根据prim的过程 T 0 T_0 T0 周围最短的一条边(距离最小的)是 ( u , v ) (u,v) (u,v) ,所以 ( x , y ) (x,y) (x,y) 的权值是大于 ( u , v ) (u,v) (u,v) 的。那么,我们不妨在正确的生成树身上做一点调整:我们把 ( x , y ) (x,y) (x,y) 删掉,换上 ( u , v ) (u,v) (u,v)

现在,我们得到的是一个生成树吗?我想,是的。

考虑生成树的定义:恰好 n − 1 n-1 n1 条边,并且覆盖了所有的点,连通。

  • 连通: T 0 T_0 T0 内部本来是连通的, T 1 T_1 T1 也是。我用一座桥 ( u , v ) (u,v) (u,v) 把二者连接了起来,当然仍然是连通的。
  • 恰好 n − 1 n-1 n1 条边:当然是这样的。
  • 覆盖了所有的点:当然是这样的。

于是,我们得到了新的生成树。可是,新的生成树的权值更小!——我们删掉了较大的权值,又加入了较小的权值。

我们找到了比最小生成树更小的生成树?相当于是 x < 0 x<0 x<0 的非负实数解。不存在的!

所以 p r i m prim prim 是没有错误的。没有错误,意味着是正确的。

后话

我曾经不相信 p r i m prim prim 是正确的,想通后写了这篇博客。

但当时自己写的并不好(而且这是我的第一篇博客 -_-#)。

现在重新修改了两三下——因为这篇博客的阅读量最多。我也不知道为什么,我明明感觉这篇博客是没有什么技术含量的啊?

我为这篇博客的未修改版道歉!(因为我自己都看不下去)

你可能感兴趣的:(C++,#,树,图论)