1、算法概述
用于生成连通无向图的最小代价生成树。
2、算法步骤
步骤一:树T初始状态为空;
步骤二:从图中任意选取一个点加入T;
步骤三:从图中找出能与T形成树的所有边,将代价最小的边加入T,形成新的树T;
步骤四:检查T中边的条数;
步骤五:如果条数小于n-1,返回步骤三,否则程序结束,T为最小代价生成树。
3、算法证明
要证明Prim算法生成的是最小生成树,我们分两步来证明:
(1)Prim算法一定能得到一个生成树;
(2)该生成树具有最小代价。
证明如下:
(1)Prim算法每次引入一个新边,都恰好引入一个新节点:如果少于1个,则新加入的边的两个端点已经在树中,引入新边后就会形成回路;如果多于一个,即2个,则这条边的两个端点都不在树中,这条边与原来的树就独立了,不再构成一个新的树。
由于第一步中已直接引入了一个顶点,所以只需再引入n-1条边(即n-1个顶点)即可。
假设Prim算法引入边数小于n-1,就意味着还有剩余的点与已生成的树没有相连,且剩余的点中没有任何点可以和树中的点连通,而由于原图是连通的,所以不可能存在这种情况,因此Prim算法不可能在此之前结束。
因此Prim算法必能引入n-1条边,此时得到的树是原图的生成树。
(2)下面我们用循环不变式证明生成的树具有最小代价。循环不变式如下:
假设每次引入新的边后形成的树T包含的点集为X,X中点与点之间的所有边构成一个子图G0,则T是G0的最小代价生成树。
初始化:引入新边之前,先直接引入一个点,由于此时G0中只有一个点,因此该点就是G的最小代价生成树。
保持:令
引入新边前的树是T0,点集是X0,构成的子图是G0,引入的边是e,相应的点是y;
得到新的树是T1,点集是X1=X0+y,构成的子图是G1。
假设T1不是G1的最小生成树,我们必然可以在G1中其它边中找到一条边d,由于T1本身是树,d加入后形成回路,回路中有代价大于d的边,将其中之一f删掉,从而得到代价更小的树。
首先d两个端点不可能都在G0中:否则f必然是T0中的边,这就意味着在T0中加入d,减去f可以得到代价更小的树,这与T0是G0的最小生产树矛盾;
因此,如果d存在,则必然是从y发出,连接G0中某个点。
e是y连接T0的边中最小的边:因为y与T0独立,所以y与T0相连的边,任意选一条加入都不会构成回路,即得到的仍然是树,因此e只需从这些边中选择代价最小的即可。
因此,所以d的代价大于等于e小于f。d,e,f位于一个环路上,f是环路中代价最大的边,或最大的边之一,且先于d、e被引入生成树。
1)假设f是代价最大的边,因为每次只能引入一个新节点,因此f两个端点必然有一个先于另一个被引入,而该点引出的边中,有小于f的,所以会先选择其他边,继而又可以依次引出环路上其它边,包括d、e,所以f不可能在d、e之前被引入,因此这种情况不可能存在;
2)假设f是代价最大的边之一,即环路中存在若干条代价等于f的最大边。这若干条可以是相邻的,也可以是不相邻的。我们可以想象这是一个环形,从y出发, 沿着d、e两个方向向两边延伸,直到两端都遇到最大边位为止,假设这是遇到的两个端点分别是y1、y2,根据Prim原则,这两个端点不可能同时进入树 中,假设y1先进入,因为通过y1可以引入边d、e,且d、e的代价都小于y2对应的那条最大边,因此y2对应的最大边绝不会在d、e之前进入树中,因此 这种情况也不可能发生。
综上1)、2)可知,d不存在,从而也就证明了T1是G1子图的最小生成树。
终止:算法结束时,图中所有点全部被加入树中,得到所有点(整个图)构成的最小代价生成树。
证明结束。