最小生成树prim算法

来源:互联网 发布:优化理论与方法第二版 编辑:程序博客网 时间:2024/06/07 04:45
最小生成树的由来,就是要现在n个城市之间建立道路,那么联通这n个城市至少需要n-1条路径,那问题就来了,如何建造这些路径使得最终的花费最小呢。这就用到了最小生成树了,也就是说找出点之间的一些边,然后把这些边挑出来组成一棵树。
生成最小生成树的方法有很多种,但是都是基于一种MST的思想,假设一个网络中 (带权图中),V表示顶点集合,E表示边的集合,U是V的一个非空子集,如果(u,v)是一条具有最小代价的边,其中u属于U,而v数据与V-U,那么必然存在一个最小生成树,包含此条边。
用反证法证明:假设网络N中有一个最小是生成树T,那么如果把(u,v)这条边加到T中那T必然会产生回路(生成树的定义可知),这个回路必然包含(u,v)。因为T是最小生成树,那么其必然存在一条边(u',v'),当然且u与u',v与v'必然会存在一条通路,删除(u',v')则会消除环路 生成另外一个最小生成树 T',那么问题来了 T'肯定是比T的代价小的,因为(u,v)代价比(u',v')小,这样的话就和假设矛盾了,所以原来的陈述是正确的。

prim算法 其实也就是这个思想,首先它先选择一个节点作为开始节点,然后找出与它相连的边里面权值最小并把这个边和这个点加入到生成树里面,然后再找出与现在生成树的点相连的所有边中权值最小的,并把其加入到现有生成树之中,当所有点都遍历完之后就结束了,生成树也生成了。接下来看代码吧

#include <iostream>
#define MAX 200
#define NUM 9
using namespace std;
int a[NUM ][NUM ]={{0,10, MAX, MAX, MAX,11, MAX ,MAX , MAX},
{10,0,18, MAX, MAX, MAX,16, MAX ,12},
{ MAX,18,0,22, MAX ,MAX , MAX, MAX,8},
{ MAX, MAX,22,0,20, MAX ,24,16,21},
{ MAX, MAX, MAX,20,0,26, MAX ,7,MAX },
{11, MAX, MAX, MAX,26,0,17, MAX ,MAX },
{ MAX,16, MAX ,24,MAX ,17,0,19, MAX},
{ MAX, MAX, MAX,16,7, MAX ,19,0,MAX },
{ MAX,12,8,21, MAX ,MAX , MAX, MAX,0}
};//邻接矩阵方法定义了图(网络),其原型为
typedef struct tempedg
{
        int source;
        int des;
        int weight;
} tempedge; //定义临时 边的存放结构,source为边的七点,des为边的终点,weight为边的权重
tempedg FindMin(tempedg * temp, int length )
{
        tempedg tempres=temp [0];
        int min=temp [0].weight;
        for (int i=1;i< length;i++)
       {
               if (temp [i].weight<min)
              {
                     min= temp [i].weight;
                     tempres= temp [i];
              }
       }
        return tempres;
}//在一群候选边中找出权值最小的候选边,应返回这条边
int FindPoint(int * p, int bobefind, int length )
{
        int flag=0;
        for (int i=0;i< length;i++)
       {
               if (p [i]== bobefind)
              {
                     flag=1;
                      break ;
              }
       }
        return flag;
}//查找 候选点是否已经在点集中,如果在就不要选这条边,因为这样会形成环路
void Prim(int g[][9])
{
       
        int points[9],pointflag=1,min,k=0,flag=-1;
       points[0]=0;
        tempedg tempmin[9];
        while (pointflag!=9) //边界条件 将所有的点都加到生成树中
       {
               for (int j=0;j<pointflag;j++)//遍历points数组
              {
                     min= MAX ;
                     tempmin[j].weight= MAX ;
                      for (int i=0;i< NUM;i++)//找出每个节点所连的边中哪条权值最小
                     {     //找出每个候选点所连接的边中权值最小的,并且找和已有节点之间的边
                             if (g [points[j]][i]<min&&!FindPoint(points,i,pointflag)) 
                           {
                                  min= g [points[j]][i];
                                  tempmin[j].weight=min;
                                  tempmin[j].source=points[j];
                                  tempmin[j].des=i;
                           }
                     }
              }
               tempedg tempres;
              tempres=FindMin(tempmin,pointflag);//在所有候选边中找出最优的。
              cout<<tempres.source<< " "<<tempres.des<< " "<<tempres.weight<<endl;
              pointflag++;//候选点数据长度+1
              points[pointflag-1]=tempres.des;
       }
}

int main()
{
       Prim(a);
        return 0;
}
0 0
原创粉丝点击