最小生成树的PRIM算法(c++实现)

  在网络搭建中,最小生成树有其广泛的应用.本文是作者学习了PRIM算法实现最小生成树之后的笔记体会.欢迎指正批评.

 

1.概述

  设G =(V,E)是无向连通带权图,即一个网络。E中每条边(v,w)的权为c[v][w]。如果G的子图G’是一棵包含G的所有顶点的树,则称G’为G的生成树。生成树上各边权的总和称为该生成树的耗费。在G的所有生成树中,耗费最小的生成树称为G的最小生成树

     网络的最小生成树在实际中有广泛应用。例如,在设计通信网络时,用图的顶点表示城市,用边(v,w)的权c[v][w]表示建立城市v和城市w之间的通信线路所需的费用,则最小生成树就给出了建立通信网络的最经济的方案。

  最小生成树性质:

   设G=(V,E)是连通带权图,U是V的真子集。如果(u,v)属于E,且u属于U,v属于V-U,且在所有这样的边中,(u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,它以(u,v)为其中一条边。这个性质有时也称为MST性质。

 

2.PRIM算法

  设G=(V,E)是连通带权图,V={1,2,…,n}。

  构造G的最小生成树的Prim算法的基本思想是:首先置S={1},然后,只要S是V的真子集,就作如下的贪心选择:选取满足条件i属于S,j属于V-S,且c[i][j]最小的边,将顶点j添加到S中。这个过程一直进行到S=V时为止。

  在这个过程中选取到的所有边恰好构成G的一棵最小生成树。

  利用最小生成树性质和数学归纳法容易证明,上述算法中的边集合T始终包含G的某棵最小生成树中的边。因此,在算法结束时,T中的所有边构成G的一棵最小生成树。

  例如,对于右图中的带权图,按Prim算法选取边的过程如下页图所示。  

按Prim算法选取边的过程如下页图所示。

  在上述Prim算法中,还应当考虑如何有效地找出满足条件i在S中,j也在V-S中,且权c[i][j]最小的边(i,j)。实现这个目的的较简单的办法是设置2个数组closest和lowcost。

  在Prim算法执行过程中,先找出V-S中使lowcost值最小的顶点j,然后根据数组closest选取边(j,closest[j]),最后将j添加到S中,并对closest和lowcost作必要的修改。

  用这个办法实现的Prim算法所需的计算时间为O(n2).

 

以下是我参考<计算机算法分析与设计>王晓东第三版的代码设计的程序.

#include <iostream>
#define MAXINT 6

using namespace std;

//声明一个二维数组,C[i][j]存储的是点i到点j的边的权值,如果不可达,则用1000表示
//借此二维数组来表示一个连通带权图
int c[MAXINT][MAXINT]={{1000,6,1,5,1000,1000},{6,1000,5,1000,3,1000},{1,5,1000,5,6,4},{5,1000,5,1000,1000,2},{1000,3,6,1000,1000,6},{1000,1000,4,2,6,1000}};
void Prim(int n)
{
    int lowcost[MAXINT];//存储S中到达对应的其它各点的最小权值分别是多少
    int closest[MAXINT];//closest[]数组保存的是未在S中的点所到达S中包含的最近的点是哪一个,如:closest[i]=1表示i最靠近的S中的点是1
    bool s[MAXINT];//bool型变量的S数组表示i是否已经包括在S中
    int i,k;
    s[0]=true;//从第一个结点开始寻找,扩展
    for(i=1;i<=n;i++)//简单初始化
    {
        lowcost[i]=c[0][i];
        closest[i]=0;//现在所有的点对应的已经在S中的最近的点是1
        s[i]=false;
    }
    cout<<"0->";
    for(i=0;i<n;i++)
    {
        int min=1000;//最小值,设大一点的值,后面用来记录lowcost数组中的最小值
        int j=1;
        for(k=1;k<=n;k++)//寻找lowcost中的最小值
        {
            if((lowcost[k]<min)&&(!s[k]))
            {
                min=lowcost[k];j=k;
            }
        }
        cout<<j<<" "<<"->";
        s[j]=true;//添加点j到集合S中
        for(k=1;k<=n;k++)//因为新加入了j点,所以要查找新加入的j点到未在S中的点K中的权值是不是可以因此更小
        {
            if((c[j][k]<lowcost[k])&&(!s[k])){lowcost[k]=c[j][k];closest[k]=j;}
        }
    }

}
int main()
{
    
    //输入初始化数组

    cout<<"请输入初始权值数组:"<<endl;
    for(int i=0;i<MAXINT;i++)
    {
        for(int j=0;j<MAXINT;j++)
        {
        //    cout<<"please enter c["<<i<<"]["<<j<<"]:";
        //    cin>>c[i][j];
            cout<<c[i][j]<<"\t";
        //    cout<<endl;
        }
        cout<<endl;
    }
    
    Prim(MAXINT-1);
    return 0;




}

 

 

 

 

 

 

  

posted @ 2012-04-27 21:35  jianglirui  阅读(11245)  评论(0编辑  收藏  举报