关于最小生成树的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; }