【问题描述】
城市之间的公路交通可以用一个无向图表示。如下图所示:
顶点表示城市、边表示城市之间有公路相连,边上的权值表示城市之间的公路长度。
编程解决以下问题:
(1)输入城市信息和城市之间公路的信息,建立图的邻接矩阵存储结构
(2)为了使城市之间能够通信,将沿公路铺设光纤,给出合理的方案,使得光纤总耗费最小。
【输入形式】
第一行输入城市,城市之间用空格分开,输入q结束。
后面若干行,每行输入两座城市及城市间的公路长度,用空格分开。输入q结束。
输入起点城市名称。
【输出形式】起点城市出发得到的最小生成树,输出格式为(起点城市, 终点城市).
注:城市之间是英文逗号,并且没有空格。
【样例输入】
成都 西安 昆明 贵阳 武汉 株洲 q
成都 西安 842
成都 昆明 1100
成都 贵阳 967
西安 武汉 740
贵阳 武汉 1042
贵阳 株洲 607
武汉 株洲 409
q
成都
注意事项
1. 录入边信息时,由于是无向图是对称矩阵,所以邻接矩阵对称位置都要记录边的权值。
2. 每加入一个顶点,所有未加入顶点都要更新 closedge 数组的内容。
在最后附有总的代码!!!
步骤:
一、建立图的邻接矩阵存储结构
1、定义图的数组存储的结构体类型。
#define MaxVertexNum 25 /*最大顶点数设为 25*/
#define INF 32767 /*INF 表示∞*/
typedef int EdgeType; /*边的权值设为整型*/
typedef struct /*邻接矩阵类型定义*/
{
char vexs[MaxVertexNum][10]; /*顶点表成都,武汉...*/
EdgeType edges[MaxVertexNum][MaxVertexNum]; /*邻接矩阵,即边表*/
int n, e; /*顶点数和边数*/
}MGraph;
2、定义创建图的存储的函数。
/*返回顶点城市在顶点数组vexs 中序号,没有该城市名返回-1*/
int VexID(MGraph *G,char VexName[])
{
int i;
for(i = 0; i < G -> n; i ++)
{
if(strcmp(VexName, G->vexs[i]) == 0)
break;
}
if(i == G->n)
return -1;
else
return i;
}
void createGraph(MGraph *G)
{
int i, j, k, l;
char t[10], m[10];
/*记录顶点信息*/
printf("\n 请依次输入城市名,输入 q 退出:\n");
for(i = 0; i < MaxVertexNum; i ++)
{
printf("\n 序号为%d的城市名称:", i);
scanf("%s", G->vexs[i]);
/***完善下列代码****/ /*如果输入q,退出循环*/
if(strcmp(G->vexs[i],"q")==0) //比较字符串
break;
G->n++; /*记录输入顶点数目*/
}
/*初始化邻接矩阵*/
/***完善下列代码****/ /*邻接矩阵主对角线上元素为0,其余为INF*/
for(i=0;i<G->n;i++)
{
for(i=0;i<G->n;i++)
{
if(i==j)
{
G->edges[i][j] = 0;
}
else
G->edges[i][j] = INF;
}
}
/*记录边信息*/
printf("\n 请输入边的信息,输入 q 退出:\n");
for(i = 0; ; i ++)
{
printf("\n 起始顶点:");
scanf("%s", t);
if(strcmp(t, "q") == 0)
break;
printf("\n 终止顶点:");
scanf("%s", m);
printf("\n 边的权重:");
scanf("%d", &l);
j = VexID(G, t);
k = VexID(G, m);
/***完善下列代码****/ ;/*在邻接矩阵对应位置记录边的权值*/
if(j!=-1 && k!=-1)
{
G->edges[j][k] = l; //无向图需要双向标记
G->edges[k][j] = l;
//G->e++; //边数加一
}
else
{
printf("输入的顶点信息有误!");
i--;
}
}
G->e = i; /*记录边的数目*/
}
二、编写最小生成树算法。
/*定义 Closedge 数组类型,作为普里姆算法的辅助数组类型*/
typedef struct
{
int adjvex; //目标点
int lowcost; //到目标点的最短距离
}Closedge;
/*输出最小生成树的普里姆算法。*/
void Prim(MGraph *G,char *startCity)
{ /*G 为图的邻接矩阵存储,startCity 是起点城市名称*/
/*算法将依次输出需要铺设光缆的公路*/
int k, j, i, minCost;
Closedge closedge[MaxVertexNum]; /*定义辅助数组*/
int v = VexID(G, startCity);
if(v < 0)
{
printf("输入的起点城市错误!\n");
return;
}
closedge[v].lowcost = 0; //初始化所有的最短距离为0
for (j = 0; j < G->n; j ++) /*初始化 closedge 数组*/
{ /***完善下列代码****/
if(j!=v)
{
closedge[j].adjvex = v; //依此将顶点存入closedge数组
closedge[j].lowcost = G->edges[v][j]; //依此将边存入closedge数组
}
}
for (i = 1; i < G->n; i ++) /*依次将顶点加入到集合 U 中*/
{
for(j = 0; j < G->n; j++)/*定位第一个没有加入到 U 中的顶点*/
if(closedge[j].lowcost != 0)
{
k = j;
break;
}
minCost = closedge[k].lowcost; /*定位V-U集合中 lowcost最小的顶点*/
for (j = 0; j < G->n; j ++)
if (closedge[j].lowcost < minCost && closedge[j].lowcost != 0)
{
/***完善下列代码****/
k = j;
minCost = closedge[j].lowcost;
}
printf("(%s,%s)\n", G->vexs[closedge[k].adjvex], G->vexs[k]); /*输出新边加入到树中的边*/
/***完善下列代码****/ /*将该顶点加入到集合 U*/
closedge[k].lowcost = 0;
for (j = 0; j < G->n; j ++) /*更新 closedge 数组的内容*/
{/***完善下列代码****/
if((G->edges[k][j] < closedge[j].lowcost)&& (G->edges[k][j] != 0 ))
{
closedge[j].adjvex = k;
closedge[j].lowcost = G->edges[k][j];
}
}
}
}
三、编写主函数
int main(int argn,char *argv[])
{
int select, i, j;
char c[10];
MGraph *G;
char startCity[1024];
G = (MGraph *)malloc(sizeof(MGraph));
G->n = G->e = 0;
createGraph(G);
fflush(stdin);
gets(startCity);//输入出发城市
Prim(G, startCity);
return 0;
}
总的代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MaxVertexNum 25 /*最大顶点数设为 25*/
#define INF 32767 /*INF 表示∞*/
typedef int EdgeType; /*边的权值设为整型*/
typedef struct /*邻接矩阵类型定义*/
{
char vexs[MaxVertexNum][10]; /*顶点表成都,武汉...*/
EdgeType edges[MaxVertexNum][MaxVertexNum]; /*邻接矩阵,即边表*/
int n, e; /*顶点数和边数*/
}MGraph;
/*定义 Closedge 数组类型,作为普里姆算法的辅助数组类型*/
typedef struct
{
int adjvex; //目标点
int lowcost; //到目标点的最短距离
}Closedge;
/*返回顶点城市在顶点数组vexs 中序号,没有该城市名返回-1*/
int VexID(MGraph *G,char VexName[])
{
int i;
for(i = 0; i < G -> n; i ++)
{
if(strcmp(VexName, G->vexs[i]) == 0)
break;
}
if(i == G->n)
return -1;
else
return i;
}
void createGraph(MGraph *G)
{
int i, j, k, l;
char t[10], m[10];
/*记录顶点信息*/
printf("\n 请依次输入城市名,输入 q 退出:\n");
for(i = 0; i < MaxVertexNum; i ++)
{
printf("\n 序号为%d的城市名称:", i);
scanf("%s", G->vexs[i]);
/***完善下列代码****/ /*如果输入q,退出循环*/
if(strcmp(G->vexs[i],"q")==0) //比较字符串
break;
G->n++; /*记录输入顶点数目*/
}
/*初始化邻接矩阵*/
/***完善下列代码****/ /*邻接矩阵主对角线上元素为0,其余为INF*/
for(i=0;i<G->n;i++)
{
for(i=0;i<G->n;i++)
{
if(i==j)
{
G->edges[i][j] = 0;
}
else
G->edges[i][j] = INF;
}
}
/*记录边信息*/
printf("\n 请输入边的信息,输入 q 退出:\n");
for(i = 0; ; i ++)
{
printf("\n 起始顶点:");
scanf("%s", t);
if(strcmp(t, "q") == 0)
break;
printf("\n 终止顶点:");
scanf("%s", m);
printf("\n 边的权重:");
scanf("%d", &l);
j = VexID(G, t);
k = VexID(G, m);
/***完善下列代码****/ ;/*在邻接矩阵对应位置记录边的权值*/
if(j!=-1 && k!=-1)
{
G->edges[j][k] = l; //无向图需要双向标记
G->edges[k][j] = l;
//G->e++; //边数加一
}
else
{
printf("输入的顶点信息有误!");
i--;
}
}
G->e = i; /*记录边的数目*/
}
/*输出最小生成树的普里姆算法。*/
void Prim(MGraph *G,char *startCity)
{ /*G 为图的邻接矩阵存储,startCity 是起点城市名称*/
/*算法将依次输出需要铺设光缆的公路*/
int k, j, i, minCost;
Closedge closedge[MaxVertexNum]; /*定义辅助数组*/
int v = VexID(G, startCity);
if(v < 0)
{
printf("输入的起点城市错误!\n");
return;
}
closedge[v].lowcost = 0; //初始化所有的最短距离为0
for (j = 0; j < G->n; j ++) /*初始化 closedge 数组*/
{ /***完善下列代码****/
if(j!=v)
{
closedge[j].adjvex = v; //依此将顶点存入closedge数组
closedge[j].lowcost = G->edges[v][j]; //依此将边存入closedge数组
}
}
for (i = 1; i < G->n; i ++) /*依次将顶点加入到集合 U 中*/
{
for(j = 0; j < G->n; j++)/*定位第一个没有加入到 U 中的顶点*/
if(closedge[j].lowcost != 0)
{
k = j;
break;
}
minCost = closedge[k].lowcost; /*定位V-U集合中 lowcost最小的顶点*/
for (j = 0; j < G->n; j ++)
if (closedge[j].lowcost < minCost && closedge[j].lowcost != 0)
{
/***完善下列代码****/
k = j;
minCost = closedge[j].lowcost;
}
printf("(%s,%s)\n", G->vexs[closedge[k].adjvex], G->vexs[k]); /*输出新边加入到树中的边*/
/***完善下列代码****/ /*将该顶点加入到集合 U*/
closedge[k].lowcost = 0;
for (j = 0; j < G->n; j ++) /*更新 closedge 数组的内容*/
{/***完善下列代码****/
if((G->edges[k][j] < closedge[j].lowcost)&& (G->edges[k][j] != 0 ))
{
closedge[j].adjvex = k;
closedge[j].lowcost = G->edges[k][j];
}
}
}
}
int main(int argn,char *argv[])
{
int select, i, j;
char c[10];
MGraph *G;
char startCity[1024];
G = (MGraph *)malloc(sizeof(MGraph));
G->n = G->e = 0;
createGraph(G);
fflush(stdin);
gets(startCity);//输入出发城市
Prim(G, startCity);
return 0;
}