//
//author: cqm //
//date: 2004-9-23 //
//description:Undigraph MST //
//
#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);
}
}