关于最小生成树的prim算法原理这里不多做介绍了。与kruskal算法相比,都是利用了贪心策略来求最小生成树,不同的是:
Kruskal算法中,集合A是一个森林;选择最小的权值边加入到森林。
Prim算法中,集合A则是一棵树;每次加入到A中的安全边永远是连接A和A之外某个结点的边中权重最小的边。相当于树的生长。
下面是Prim算法的代码,里面有详细的注释:
#include<stdio.h>
#include<stdlib.h>
#define n 9//图中点的个数
#define max n*n//图中的边的个数
#define inf 9999//标示无穷大
struct edge{
int u;//起点
int v;//终点
int value;//边的权值
}e[max];
int p[n];//p[i]用于记录依次加入最小生成树的顶点
/*-----------------------------prim算法-----------------------------*/
int prim(int en[][n],int v)
{
int i,j,k,kk=0,min=inf,count=0;//min标示无穷大,count用于记录最小生成树各边的权值
int lowcost[n];//lowcost[i]用于记录顶点i到最小生成树t中的顶点的最短路径权值
int intree[n];//intree[i]用于记录顶点i是否在最小生成树中,1:在;0:不在。
for(i=0;i<n;i++)//初始化
{
if(en[i][v]==inf)//路径不可达
lowcost[i]=inf;
else //有可达路径
lowcost[i]=en[i][v];
intree[i]=0;
p[i]=-1;
}
intree[v]=1;//标记顶点v为最小生成树中的顶点
p[0]=v;
for(i=0;i<n-1;i++)//选择其余的n-1个顶点
{
min=inf;
for(j=0;j<n;j++)//选出到最小生成树t中顶点最短的顶点k
{
if(intree[j]==0 && lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
}
count=count+min;//记录权值
intree[k]=1;
v=k;
p[++kk]=k;//记录依次加入最小生成树的顶点
/**
**开始时,lowcost[]是记录其他点到v(这时v是根结点)的距离
**当新加入一个结点k后,令v=k,在剩下的未加入结点中寻找,如果v到某点j的距离小于lowcost[j],更新lowcost[j]
**这也就是prim算法的贪心策略
*/
for(j=0;j<n;j++)
{
if(intree[j]==0 && en[v][j]!=0 && en[v][j]<lowcost[j])
lowcost[j]=en[v][j];
}
}
return(count);
}
/*-----------------------------主函数-------------------------------*/
int main()
{
int i,sum=0;
char vex;
//en表示各个点之间的连接情况,为inf表示无边,其他值表示边的权值看 :)
int en[n][n]={{0,4,inf,inf,inf,inf,inf,8,inf},
{4,0,8,inf,inf,inf,inf,11,inf},
{inf,8,0,7,inf,4,inf,inf,2},
{inf,inf,7,0,9,14,inf,inf,inf},
{inf,inf,inf,9,0,10,inf,inf,inf},
{inf,inf,4,14,10,0,2,inf,inf},
{inf,inf,inf,inf,inf,2,0,1,6},
{8,11,inf,inf,inf,inf,1,0,7},
{inf,inf,2,inf,inf,inf,6,7,0}};
printf("输入最小生成树的构造开始顶点(a,b,c,d,e,f,g,h,i):\n");
scanf("%c",&vex);
sum=prim(en,vex-'a');
printf("最小生成树的代价为:%d\n",sum);
printf("构造最小生成树依次加入树的顶点为:\n");
for(i=0;i<n-1;i++)
if(p[i]!=-1)
printf("%c -> ",p[i]+'a');
printf("%c\n",p[i]+'a');
return 0;
}