此处以最小生成树为例。最大生成树,其实也是可以使用 p r i m prim prim 的。 P r i m Prim Prim 的过程是:
首先,任意选择一个点,作为一个连通块。接下来,重复执行下面的步骤,直到所有点都被加入了连通块中:
有一个特点,就是新加入的点一定与当前联通块中的某个点直接相邻。
利用一种反证法。我们假设某一步搞错了,看看接下来会发生什么。
这里的“出错”,我们定义成:加入了一条错误的边(它本不属于最小生成树,但程序误认为其应当属于)。
无论怎么说,只选择了一个点的时候是一定正确的——此时一条边也没有,怎么会有搞错的边呢?
假设某一次加边,加错了!在此之前,我们所加入的边都是正确的。
不妨设原本正确的连通块是 T 0 T_0 T0 ,此时加入了一条出错的边 ( u , v ) (u,v) (u,v) ,那么整个程序结束后应该长这样:
生成树包含每一个点,所以 T 0 + T 1 = V T_0+T_1=V T0+T1=V 。此处的 V V V 指的是所有的点。
正确的生成树是什么呢?应该是
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 n−1 条边,并且覆盖了所有的点,连通。
于是,我们得到了新的生成树。可是,新的生成树的权值更小!——我们删掉了较大的权值,又加入了较小的权值。
我们找到了比最小生成树更小的生成树?相当于是 x < 0 x<0 x<0 的非负实数解。不存在的!
所以 p r i m prim prim 是没有错误的。没有错误,意味着是正确的。
我曾经不相信 p r i m prim prim 是正确的,想通后写了这篇博客。
但当时自己写的并不好(而且这是我的第一篇博客 -_-#)。
现在重新修改了两三下——因为这篇博客的阅读量最多。我也不知道为什么,我明明感觉这篇博客是没有什么技术含量的啊?
我为这篇博客的未修改版道歉!(因为我自己都看不下去)