实验目的:掌握图的存储方法和最短路经算法。
实验内容:设计一个校园导游程序,为来访客人提供各种信息查询服务。测试数据根据实际情况指定。提示:一般情况下,校园的道路是双向通行的,可设校园平面图是一个无向图。顶点和边均含有相关信息。
实验要求:
1、设计西海岸校园平面图,所含Point of Interest(PoI)不少于10个。以图中顶点表示校内各PoI,存放PoI名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。(4分)
2、为来访客人提供图中任意PoI相关信息的查询。(2分)
3、为来访客人提供图中任意PoI的纹路查询,即查询任意两个PoI之间的一条最短的简单路径。(4分)
C语言代码如下:
/*
实验题目:校园导游咨询
实验目的:掌握图的存储方法和最短路经算法。
实验内容:设计一个校园导游程序,为来访客人提供各种信息查询服务。
测试数据根据实际情况指定。
提示:一般情况下,校园的道路是双向通行的,可设校园平面图是一个无向图。
顶点和边均含有相关信息。
实验要求:
1、设计西海岸校园平面图,所含Point of Interest(PoI)不少于10个。
以图中顶点表示校内各PoI,存放PoI名称、代号、简介等信息;
以边表示路径,存放路径长度等相关信息。(4分)
2、为来访客人提供图中任意PoI相关信息的查询。(2分)
3、为来访客人提供图中任意PoI的纹路查询,
即查询任意两个PoI之间的一条最短的简单路径。(4分)
*/
/*测试用例
10 10
0 东海 海纳百川,取则行远。
1 听海餐厅 人间有味是清欢。
2 电子信息楼 谨防电信诈骗!
3 学习综合体 非学无以广才,非志无以成学。
4 计算机楼 计算万物,机敏过人。
5 大门 一夫当关,万夫莫开。
6 海洋生物资源开发中心 连弩射海鱼,长鲸正崔嵬。
7 体育中心 发展体育运动,增强人民体质。
8 医务室 救人一命,胜造七级浮屠。
9 望海餐厅 金樽清酒斗十千,玉盘珍羞直万钱。
0 1 800
1 2 100
1 5 200
2 3 50
3 4 50
5 7 100
6 7 100
6 8 100
7 9 100
8 9 100
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VertexMax 10 //最大顶点数为10
#define MaxInt 32767 //表示最大整数,表示 ∞
typedef struct
{
char name[30]; //名称
int id; //代号
char info[50]; //简介
}PoI;//存放顶点PoI信息
typedef struct
{
PoI Vertex[VertexMax]; //存放顶点PoI元素的一维数组
int AdjMatrix[VertexMax][VertexMax];//存放边长度的邻接矩阵二维数组
int vexnum,arcnum; //记录图的顶点数和边数
}MGraph;//图=顶点+边
//实验要求1、设计西海岸校园平面图,所含Point of Interest(PoI)不少于10个。
//以图中顶点表示校内各PoI,存放PoI名称、代号、简介等信息;
//以边表示路径,存放路径长度等相关信息。(4分)
void createG(MGraph *G)
{
int i,j;
//1.输入顶点数和边数
printf("输入顶点个数和边数(中间用空格隔开):");
scanf("%d %d",&G->vexnum,&G->arcnum);
//2.输入顶点元素
printf("输入顶点元素PoI代号(0-9)、名称、简介(中间用空格隔开):\n");
for(i=0;i<G->vexnum;i++)
{
scanf("%d",&G->Vertex[i].id);
scanf(" %s",&G->Vertex[i].name);
scanf(" %s",&G->Vertex[i].info);
//输出测试
// printf("input%d展示:id = %d,name = %s,info = %s\n",
// i,G->Vertex[i].id,G->Vertex[i].name,G->Vertex[i].info);
}
//3.邻接矩阵元素初始化(对角线位置设为0,非对角线位置设为无穷)
for(i=0;i<G->vexnum;i++)
{
for(j=0;j<G->vexnum;j++)
{
G->AdjMatrix[i][j]=MaxInt;
}
}
//4.构建邻接矩阵存储边信息
PoI v1,v2;
int w;//v1->v2的权值
printf("输入路径(两个顶点的代号)及路径长度(中间用空格隔开):\n");
for(i=0;i<G->arcnum;i++)
{
printf("输入第%d条路径信息:",i+1);
scanf("%d %d %d",&v1.id,&v2.id,&w);
//因为是无向图,所以邻接矩阵对称位置也要赋相同值
G->AdjMatrix[v1.id][v2.id]=G->AdjMatrix[v2.id][v1.id]=w;
}
}
void display(MGraph G)
{
int i,j;
printf("全部PoI:\n\n");
printf("\t代号\t名称\t\t\t简介\n");
for(i=0;i<G.vexnum;i++)
{
printf("\t%d\t%-20s\t%-50s\n",
G.Vertex[i].id,G.Vertex[i].name,G.Vertex[i].info);
}
printf("\n邻接矩阵:\n\n");
printf("\t代号 ");
for(i=0;i<G.vexnum;i++)
{
printf("\t(%d)",G.Vertex[i].id);
}
printf("\n");
for(i=0;i<G.vexnum;i++)
{
printf("\t(%d)",G.Vertex[i].id);
for(j=0;j<G.vexnum;j++)
{
if(G.AdjMatrix[i][j]==MaxInt)
{
printf("\t∞");
}else
{
printf("\t%d",G.AdjMatrix[i][j]);
}
}
printf("\n");
}
}
//实验要求2、为来访客人提供图中任意PoI相关信息的查询。(2分)
int search(MGraph G)
{
printf("请输入PoI的代号或名称:");
int i,id;
char c[30];
scanf("%s",c);
if(c[0]>='0' && c[0]<='9') //若字符数组首元素是数字则按id查找
{
id = c[0]-'0';
for(i=0;i<G.vexnum;i++)
{
if(id==G.Vertex[i].id)
{
printf("代号为 '%d' 的PoI信息:\n\n",id);
printf("\t代号\t名称\t\t\t简介\n");
printf("\t%d\t%-20s\t%-50s\n",
G.Vertex[i].id,G.Vertex[i].name,G.Vertex[i].info);
return i;
}
}
}else //若字符数组首元素不是数字则按name字符数组查找
{
for(i=0;i<G.vexnum;i++)
{
if(!strcmp(c,G.Vertex[i].name))
{
printf("名称为 '%s' 的PoI信息:\n\n",c);
printf("\t代号\t名称\t\t\t简介\n");
printf("\t%d\t%-20s\t%-50s\n",
G.Vertex[i].id,G.Vertex[i].name,G.Vertex[i].info);
return i;
}
}
}
printf("查无此点!\n");
return -1;
}
//输出最短路径
void displayPath(int dist[],int path[],MGraph *G,PoI start,PoI end)
{
int i,k;
int temp[VertexMax];//临时数组
PoI target;//目标地点
int loc=0;
for(i=0;i<VertexMax;i++)
{
temp[i]=-1;
}
printf("迪杰斯特拉算法结果展示:\n\n");
//打印dist数组
printf("\tdist[i]:\n\t");
for(i=0;i<G->vexnum;i++)
{
printf("\t%d",i);
}
printf("\n\t");
for(i=0;i<G->vexnum;i++)
{
printf("\t%d",dist[i]);
}
printf("\n\n");
//打印path数组
printf("\tpath[i]:\n\t");
for(i=0;i<G->vexnum;i++)
{
printf("\t%d",i);
}
printf("\n\t");
for(i=0;i<G->vexnum;i++)
{
printf("\t%d",path[i]);
}
printf("\n\n");
//输出最短路径
printf("最短路径:\n\n");
loc=end.id;
int j=0; //j统计跳数
while(loc!=-1)
{
temp[j]=loc;
loc=path[loc];
j++;
}
printf("\t%s to %s: ",start.name,end.name);
for(j=j-1;j>=0;j--)
{
printf("%s",G->Vertex[temp[j]].name);
if(j!=0){
printf("->");
}
}
printf("(总路径长度:%d米)\n\n",dist[end.id]);
for(k=0;k<20;k++)
{
temp[k]=-1;
}
}
//找到最小的dist,用于迪杰斯特拉算法
int FindMinDist(int dist[],int s[],int vexnum)
{
int i;
int loc;
int min=MaxInt+1;
for(i=0;i<vexnum;i++)
{
if(s[i]==0)//只对s[i]=0的顶点进行查找
{
if(dist[i]<min)
{
min=dist[i];
loc=i;
}
}
}
return loc;//返回dist中最小元素的下标
}
//实验要求3、为来访客人提供图中任意PoI的纹路查询,
//即查询任意两个PoI之间的一条最短的简单路径。(4分)
//采用了迪杰斯特拉算法
void shortestPath(MGraph *G)
{
PoI start,end;
printf("请输入起点的代号或名称:");
char c1[30],c2[30];
scanf("%s",c1);
//printf("c1 = %s\n",c1);
//定位start
if(c1[0]>='0' && c1[0]<='9')
{
start.id = c1[0]-'0';
for(int i=0;i<G->vexnum;i++)
{
if(start.id==G->Vertex[i].id)
{
for(int j=0;j<30;j++){
start.name[j] = G->Vertex[i].name[j];
}
for(int j=0;j<50;j++){
start.info[j] = G->Vertex[i].info[j];
}
}
}
}else{
for(int i=0;i<G->vexnum;i++)
{
if(!strcmp(c1,G->Vertex[i].name))
{
start.id = G->Vertex[i].id;
for(int j=0;j<30;j++){
start.name[j] = G->Vertex[i].name[j];
}
for(int j=0;j<50;j++){
start.info[j] = G->Vertex[i].info[j];
}
}
}
}
printf("请输入终点的代号或名称:");
scanf("%s",c2);
//printf("c2 = %s\n",c2);
//定位end
if(c2[0]>='0' && c2[0]<='9')
{
end.id = c2[0]-'0';
for(int i=0;i<G->vexnum;i++)
{
if(end.id==G->Vertex[i].id)
{
for(int j=0;j<30;j++){
end.name[j] = G->Vertex[i].name[j];
}
for(int j=0;j<50;j++){
end.info[j] = G->Vertex[i].info[j];
}
//printf("end.name = %s,end.info = %s\n",end.name,end.info);
break;
}
}
}else{
for(int i=0;i<G->vexnum;i++)
{
if(!strcmp(c2,G->Vertex[i].name))
{
end.id = G->Vertex[i].id;
for(int j=0;j<30;j++){
end.name[j] = G->Vertex[i].name[j];
}
for(int j=0;j<50;j++){
end.info[j] = G->Vertex[i].info[j];
}
//printf("end.name = %s,end.info = %s\n",end.name,end.info);
break;
}
}
}
int i,j,num;
int loc;
int min;
int dist[VertexMax];//存储最短路径长度数组
int path[VertexMax];//存储最短路径数组
int s[VertexMax];//代表集合S,用来区分是否被纳入路径
//1.初始化dist和path数组
loc=start.id; //获取源点的下标位置
for(i=0;i<G->vexnum;i++)
{
dist[i]=G->AdjMatrix[loc][i];
if(dist[i]!=MaxInt)
{
path[i]=loc;
}
else
{
path[i]=-1;
}
}
//2.初始化S数组
//s数组:代表集合S,用1代表该元素属于集合S(已处理的顶点)
//用0该元素不属于集合S(未处理的顶点)
for(i=0;i<G->vexnum;i++)
{
s[i]=0;
}
s[loc]=1;//代表起始点(源点)以处理完毕
num=1;
//3.迪杰斯特拉算法
while(num<G->vexnum)
{
min=FindMinDist(dist,s,G->vexnum);//在dist数组中查找其对应s[i]=0,即未处理的最小值元素
s[min]=1;//将找到的最短边所对应的的顶点加入集合S
for(i=0;i<G->vexnum;i++)//加入新的顶点后,更新dist和path数组
{
if((s[i]==0)&&(dist[i]>dist[min]+G->AdjMatrix[min][i]))
{
dist[i]=dist[min]+G->AdjMatrix[min][i];
path[i]=min;//min->i
}
}
num++;
}
displayPath(dist,path,G,start,end);//展示dist数组、path数组及最短路径
}
int main()
{
printf("--------------------校园导游程序--------------------\n");
MGraph G;
printf("录入数据:\n");
createG(&G);
printf("录入完成!\n");
while(true){
int choice = 0;
printf("--------------------校园导游程序--------------------\n");
printf("功能选择:0.退出程序 1.展示全部PoI和边 "
"2.查询PoI信息 3.查询最短路径\n");
printf("你的选择是:");
scanf("%d",&choice);
switch(choice){
case 0:return 0;break;
case 1:display(G);break;
case 2:search(G);break;
case 3:shortestPath(&G);break;
}
}
return 0;
}
记录一下曾经的努力,欢迎大家讨论和借鉴!