一.概念
生成图G(V,E)的最小生成树A常用的算法有两种:Kruskal算法,和Prim算法。Kruskal算法在不使A含有环的情况下,从图G中找出权值最小的边加入A,直到A中的节点数达到|V|为止。Prim算法在不使A生成环的情况下,找到A中节点到G-A中节点权值最小的边,并把找到的边加入A,直到A中节点数达到|V|为止。本文章只对Krim算法加以实现。
二.Prim算法的实现
int PRIM(int **G,int n) //G用邻接矩阵色方式保存G(V,E),G[i][j]表示边(Vi,Vj)的权值,n表示图的节点数
{ //规定G[i][i]=0,若Vi到Vj不可达则G[i][j]=0;
int* YBL=new int[n]; //若节点Vi已在最小生成树里面则YBL[i]=1,否则YBL{[i]=0;
int** JG=new int*[n]; //JG[i][0]存储生成树节点的小标,保存V(JG[i][0])节点在最小成树里面的父节点的小标
for(int i=0;i<n;i++)
{
YBL[i]=0;
JG[i]=new int[2];
}
YBL[0]=1,*((int*)JG+0*n+0)=0,*((int *)JG+0*n+1)=-1; //从V0开始生成树,也可从其他节点开始
int len=0; //用于保存JG已有节点数-1
int min=100,_min,F,sum=0; //min应取值无穷大,但为了比较方便此处取100,取值应大于边的最大权值
L: for(int i=0;i<n;i++)
{
if(len==n-1)
break;
if(YBL[i]==1) //保证了Vi节点已在生成树中
{
for(int j=0;j<n;j++)
{
if(((*((int *)G+i*n+j))<min)&&((*((int *)G+i*n+j))!=0)&&(YBL[j]==0)) //保证Vj没在生成树中,且(Vi,Vj)权值最小
{
_min=j;
min=*((int *)G+i*n+j);
F=i;
}
}
}
}
if(min!=100)
{
YBL[_min]=1;
len=len+1;
*((int *)JG+len*n+0)=_min;
*((int *)JG+len*n+1)=F;
min=100;
sum=sum+*((int *)G+F*n+_min);
goto L;
}
cout<<"生成树权值和: "<<sum<<endl;
for(int i=0;i<n;i++)
cout<<"节点V"<<*((int *)JG+i*n+0)<<" 最小生成树中父节点为:V"<<*((int *)JG+i*n+1)<<endl;
return 0;
}
三.举例
int main()
{
int G[5][5]={{0,1,0,3,2},
{1,0,3,0,0},
{0,3,0,0,2},
{3,0,0,0,1},
{2,0,2,1,0}};
PRIM((int**)G,5);
return 0;
}
结果:
V-1表示V0是最小生成树的根 ,无父节点