關於最小生成樹的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;
}