#include <stdio.h> #include <malloc.h> #include <limits.h> #define INFINITY INT_MAX //INT_MAX表示最大整数,请参阅C的limits.h文件 #define n 10 //图的顶点数,应由用户定义 typedef int AdjMatrix[n][n]; //用二维数组作为邻接矩阵表示 //树边结点 typedef struct{ int fromvex,tovex; //边的起点和终点 int length; //边上的权 }TreeEdgeNode; typedef TreeEdgeNode MST[n-1]; //最小生成树类型 AdjMatrix G; //连通网的带权邻接矩阵,作为Prim算法的输入 MST T; //存放G的最小生成树,作为Prim算法的输出 //打印错误信息 void Error(char *msg) { printf("%c/n",msg); } // void CreateGraph(AdjMatrix G){ int i,j; int start,end,weight; for(i=0;i<n;i++) //n为图的顶点数 for(j=0;j<n;j++) G[i][j] = INFINITY; //INFINITY代表无穷大 printf("输入弧和其权值,格式:弧尾,弧头,权值/n"); for(i=0;i<n-1;i++){ scanf("%d %d %d",&start,&end,&weight); getchar(); G[start][end]=weight; G[end][start]=weight; } } void DefaultCreateGraph(AdjMatrix G){ int i,j; for(i=0;i<n;i++) //n为图的顶点数 for(j=0;j<n;j++) G[i][j] = INFINITY; //0-9 G[0][1]=4; G[1][0]=4; G[1][2]=2; G[2][1]=2; G[0][3]=3; G[3][0]=3; G[1][5]=1; G[5][1]=1; G[3][6]=10; G[6][3]=10; G[6][9]=5; G[9][6]=5; G[9][7]=2; G[7][9]=2; G[7][8]=6; G[8][7]=6; G[3][4]=8; G[4][3]=8; G[4][5]=1; G[5][4]=1; G[2][5]=2; G[5][2]=2; G[4][7]=4; G[7][4]=4; G[5][8]=4; G[8][5]=4; } //构造初始的时候选轻边集T[0...n-2],树边集TE!=Null,红点集U={r} void InitCandidateSet(AdjMatrix G,MST T,int r){ int i,k=0; for(i=0;i<n;i++) //依次行成每个蓝点i初始的最短紫边存放在T[k]中 if(i!=r){ //i是蓝点(r,i)是紫边 T[k].fromvex = r; //紫边的起点为红点 T[k].tovex = i; //紫边的终点为蓝点 T[k++].length= G[r][i]; //紫边长度,注:先取k然后再加一 }//endif } //在当前候选轻边集中选择一条轻边,即选择长度最短的紫边 int SelectLightEdge(MST T,int k){ //在当前候选轻边集T[k..n-2]中选择最短紫边,k<=n-2 int min = INFINITY,i,minpos; for(i=k;i<n-1;i++) //遍历当前候选轻边集,找一轻边 if(T[i].length < min){ min = T[i].length; minpos = i; //记录当前最短紫边位置 }//endif if(min==INFINITY) //表示图不连通,不能求MST Error("Graph is disconnected!"); return minpos; //返回找到的轻边T[minpos]的位置 }//end SelectLightEdge //调整候选边集 void ModifyCandidateSet(AdjMatrix G,MST T,int k,int v){ int i,d; for(i=k;i<n-1;i++){ //遍历当前候选轻边集T[k..n-2] d = G[v][T[i].tovex]; //d是新紫边(v,T[i].tovex)的长度 if(d<T[i].length){//新紫边长度小于蓝点T[i].tovex原来关联的最短紫边的长度 T[i].length = d; T[i].fromvex= v; //新紫边取代原最短紫边 }//endif }//end for }//ModifyCandidateSet //求图G的以r为根的MST,r为开始的结点 void PrimMST(AdjMatrix G,MST T,int r){ int k,m,v; TreeEdgeNode e; InitCandidateSet(G,T,r); //设置初始的轻边候选集T[0..n-2] for(k=0;k<n-1;k++){ //依次求MST的第k条树边 m = SelectLightEdge(T,k); //在当前候选轻边集T[k..n-2]中选取轻边T[m] //轻边T[m]和紫边T[k]交换,即把轻边扩充到树中 e = T[m]; T[m]= T[k]; T[k]= e; v = T[k].tovex; //交换后红色树边集为T[0..k]候选边集为T[k+1..n-2] ModifyCandidateSet(G,T,k+1,v); //根据新红点v调整候选轻边集T[k+1...n-2]扩充 }//endfor }//PrimMST void PrintMST(MST T){ int i; for(i=0;i<n-1;i++){ printf("(%d,%d)=%d/n",T[i].fromvex,T[i].tovex,T[i].length); } } //测试主函数 void main(){ int u; char j='y'; printf("本程序将演示构造图的最小代价生成树。/n"); printf("首先输入图的顶点数和弧数./n格式:顶点数,弧数;例如:4,4/n"); printf("接着输入各条弧(弧尾,弧头)和弧的权值。/n"); printf("格式:弧尾,弧头,权值;例如/n1,2,1/n1,3,2/n2,4,3/n3,4,4/n"); printf("程序将会构造该图的最小代价生成树。/n"); printf("并显示该最小生成树。/n1,2/n1,3/n2,4/n"); while(j!='N'&&j!='n') { printf("请输入图的顶点和弧数:"); DefaultCreateGraph(G); //CreateGraph(G);//生成邻接矩阵结构的图 printf("从哪一顶点开始:"); scanf("%d",&u); //输入普里姆算法中的起始顶点 PrimMST(G,T,u); //普里姆算法求最小生成树 PrintMST(T); //打印最小生成树 printf("最小代价生成树构造完毕,继续进行吗?(Y/N)"); scanf("%c",&j); } }