问题描述
问题描述
设计你的学校的平面图,至少包括10个以上的景点(场所),每两个景点间可以有不同的路,且路长也可能不同,找出从任意景点到达另一景点的最佳路径(最短路径)。
要求:
(1)以图中顶点表示校园内各景点,存放景点名称、代号、简介等信息;以边表示路径,存放路径长度等有关信息。
(2)为来访客人提供图中任意景点相关信息的查询。
(3)为来访客人提供任意景点的问路查询,即查询任意两个景点之间的一条最短路径。
(4)修改景点信息
设计思路与原因
本程序的主要目的是提供任意景点的最短路径查询,并提供相关景点信息的查询。因此先将校园平面图信息抽象为无向网,用邻接矩阵存储,再用Dijkstra或Floryd算法计算任意两景点的最短路径.>a
分析算法的时间复杂度:
(1) Void CreateMGraph(int v)
其中为顶点赋值用了一次for循环,为邻接矩阵赋值用了两次for循环且相互嵌套,故时间复杂度为O(n^2+n)
(2)void Dijkstra(int num)
其中为置空初始值用了两次for循环且相互嵌套,更新路径长度用了四次for循环且相互嵌套,故其时间复杂度为O(n^4+n^2)
(3). Void Display(int sight1,int sight2)
其中输出最短路径用了两次for循环且相互嵌套,故时间复杂度为O(n^2);
源代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define Max 32767 /*用Max来表示权值为此时的两点间直接不可达*/
#define NUM 18 /*选取了学校的十七个地点用数组存储,其中数组第一个元素不存储地点以方便操作*/
typedef struct VertexType{
int number;
char *sight;
}VertexType; /*定义顶点的结构体类型,number表示顶点编号,字符数组表示顶点的名称*/
typedef struct{
VertexType vex[NUM]
int arcs[NUM][NUM];
int vexnum;
}MGraph; /*定义图的结构体类型,vex[NUM]数组存储顶点,arcsp[NUM][NUM]矩阵存储边的权值,vexnum表示顶点的个数*/
MGraph G; /*生成G表示结构体变量MGraph*/
int P[NUM][NUM]; /*定义全局变量P[NUM][NUM]存储点之间的最短路径*/
long int D[NUM]; /*定义全局变量D[NUM]存储点之间最短路径的权值*/
void CreateMGraph(int v) /*创建图的函数,其中v表示图中的顶点数*/
{
int i,j;
G.vexnum=v;
for(i=1;i<G.vexnum;++i)
G.vex[i].number=i; /*初始化各个顶点的编号为1~17*/
G.vex[0].sight="各个景点名字"; /*为各个顶点的名称赋值,其中G.vex[0].sight不作地点名赋值*/
G.vex[1].sight="大门口";
G.vex[2].sight="行政楼";
G.vex[3].sight="北区";
G.vex[4].sight="一号教学楼";
G.vex[5].sight="二号教学楼";
G.vex[6].sight="实验楼";
G.vex[7].sight="三号教学楼";
G.vex[8].sight="图书馆";
G.vex[9].sight="开水房";
G.vex[10].sight="超市";
G.vex[11].sight="榴馨苑";
G.vex[12].sight="洗浴中心";
G.vex[13].sight="骊秀苑";
G.vex[14].sight="综合楼";
G.vex[15].sight="游泳池";
G.vex[16].sight="田径场";
G.vex[17].sight="体育馆";
for(i=1;i<G.vexnum;++i)
{
for(j=1;j<G.vexnum;++j)
G.arcs[i][j]=Max; /*初始化各条边的权值为Max*/
}
G.arcs[1][2]=G.arcs[2][1]=255;/*按实际大小为边赋权值,因为是无向图故G.arcs[i][j]=G.arcs[j][i]*/
G.arcs[1][4]=G.arcs[4][1]=501;
G.arcs[1][5]=G.arcs[5][1]=535;
G.arcs[1][6]=G.arcs[6][1]=705;
G.arcs[1][7]=G.arcs[7][1]=722;
G.arcs[1][8]=G.arcs[8][1]=790;
G.arcs[2][3]=G.arcs[3][2]=314;
G.arcs[2][4]=G.arcs[4][2]=450;
G.arcs[2][5]=G.arcs[5][2]=484;
G.arcs[2][6]=G.arcs[6][2]=654;
G.arcs[2][7]=G.arcs[7][2]=663;
G.arcs[2][8]=G.arcs[8][2]=748;
G.arcs[3][17]=G.arcs[17][3]=1054;
G.arcs[4][5]=G.arcs[5][4]=272;
G.arcs[4][6]=G.arcs[6][4]=178;
G.arcs[4][7]=G.arcs[7][4]=442;
G.arcs[4][8]=G.arcs[8][4]=527;
G.arcs[5][6]=G.arcs[6][5]=476;
G.arcs[5][7]=G.arcs[7][5]=187;
G.arcs[5][8]=G.arcs[8][5]=561;
G.arcs[6][7]=G.arcs[7][6]=289;
G.arcs[6][8]=G.arcs[8][6]=374;
G.arcs[6][9]=G.arcs[9][6]=520;
G.arcs[7][8]=G.arcs[8][7]=382;
G.arcs[8][14]=G.arcs[14][8]=365;
G.arcs[8][17]=G.arcs[17][8]=1096;
G.arcs[9][10]=G.arcs[10][9]=297;
G.arcs[10][11]=G.arcs[11][10]=178;
G.arcs[10][12]=G.arcs[12][10]=331;
G.arcs[12][13]=G.arcs[13][12]=383;
G.arcs[13][14]=G.arcs[14][13]=340;
G.arcs[13][15]=G.arcs[15][13]=1003;
G.arcs[13][16]=G.arcs[16][13]=833;
G.arcs[14][17]=G.arcs[17][14]=646;
G.arcs[15][16]=G.arcs[16][15]=714;
G.arcs[16][17]=G.arcs[17][16]=688;
}
void Map() /*地图展示函数,用于输出西安科技大学的平面简略图*/
{
printf("\n\n\n");
printf("\t ***********************欢迎来到西安科技大学*************************");
printf("\n\n\n");
printf(" ━━━━━━━━━━━━━━━15游泳池 \n");
printf(" ┃ ┃ \n");
printf(" ┃ ┃ \n");
printf("12洗浴中心━━━━━━━━━━13骊绣苑━━━━━━━━━━━━━16田径场 \n");
printf(" ┃ ┃ ┃ \n");
printf(" ┃ 14综合楼 ┃ \n");
printf("10超市━━━11榴馨苑 ┃ ┃ \n");
printf(" ┃ ┃ ┃━━━━━━━━━━━━━━17体育馆 \n");
printf("9开水房 ┃ ┃ ┃ \n");
printf(" ┃ ━━━━━━━━━8图书馆 ┃ \n");
printf(" ┃ ┃ ┃ \n");
printf(" ┃ ┃ ┃ \n");
printf(" ━━━━━━━6实验楼━━━━━┃━━━━━7三号教学楼 ┃ \n");
printf(" ┃ ┃ ┃ ┃ \n");
printf(" ┃ ┃ ┃ ┃ \n");
printf(" ┃ ┃ ┃ ┃ \n");
printf(" 4一号教学楼━━━━━┃━━━━━5二号教学楼 ┃ \n");
printf(" ┃ ┃ \n");
printf(" ┃ ┃ \n");
printf(" ┃ ┃ \n");
printf(" ┃ ┃ \n");
printf(" ┃━━2行政楼━━━━━━━━━━━━3北区 \n");
printf(" ┃ \n");
printf(" ┃ \n");
printf(" 1大门口 \n");
}
void Info() {资料介绍函数,用于当用户选择查询地点资料时输出地点的资料信息}
{
printf("1 大门口 : 出入学校的必经之路\n");
printf("2 行政楼:学校最气派的建筑之一 \n");
printf("3 北区: 金工实训中心以及9-18号教学楼\n");
printf("4 一号教学楼:主要有小教室\n");
printf("5 二号教学楼:主要用来上专业课,五六楼有语音室\n");
printf("6 实验楼: 学生上各种实验课的地点\n");
printf("7 三号教学楼:有大教室,一般安排用来上基础课\n");
printf("8 图书馆: 学校为同学们提供学习和自习的地方,也是学校的藏书最多的地方\n");
printf("9 开水房: 提供热水的地点 \n");
printf("10 超市: 学校唯一一个中型超市,在这里可以买到各种生活用品\n");
printf("11 榴馨苑: 环境较好的学生食堂,离女生公寓较近\n");
printf("12 洗浴中心: 环境还行就是规模太小,每天都是供不应求\n");
printf("13 骊秀苑: 主要经营面食。我校的物美价廉的食堂,位于男生公寓区\n");
printf("14 综合楼: 历史较为悠久的一栋教学楼,旁边有学生第二俱乐部,学校的晚会都在这里举行\n");
printf("15 游泳池: 大一学生上游泳课的地点\n");
printf("16 田径场: 上室外体育课的地点\n");
printf("17 体育馆: 上室内体育课的地方,\n");
}
void Dijkstra(int num) /*通过迪杰斯特拉算法求num点到其余点的最短路径,并将最短路径保存在数组P[NUM][NUM]中,将最短路径的权值保存在数组D[NUM]中*/
{
int v,w,i,t;
int final[NUM];
int min;
for(v=1;v<NUM;v++)
{
final[v]=0; /*置空最短路径终点集*/
D[v]=G.arcs[num][v];/*置初始的最短路径长度*/
for(w=1;w<NUM;w++)
P[v][w]=0;/*置空最短路径*/
if(D[v]<32767)
{
P[v][num]=1;
P[v][v]=1;
}
}
D[num]=0;
final[num]=1;/*初始化num顶点属于S集*/
for(i=1;i<NUM;++i)/*开始循环,每次求得num到某个顶点的最短路径,并添加到S集*/
{
min=Max; /*min为当前所知的num到顶点的最短距离*/
for(w=1;w<NUM;++w)
if(!final[w])/*w顶点在V-S集中*/
if(D[w]<min)
{
v=w;
min=D[w];
}
final[v]=1; /*与num相距最近的顶点并入S集*/
for(w=1;w<NUM;++w)/*更新最短路径*/
if(!final[w]&&((min+G.arcs[v][w])<D[w]))/*修改D[w]和P[w],w在V-S集中*/
{
D[w]=min+G.arcs[v][w];
for(t=0;t<NUM;t++)
P[w][t]=P[v][t];
P[w][w]=1;
}
}
}
char Menu()/*主菜单显示于操作界面从而让用户选择查询路径功能或者查询地点信息功能*/
{
char c;
int flag;/*定义标志flag确定循环条件*/
do{
flag=1;
Map();
printf("\t\t欢迎使用西安科技大学导航图系统\n");
printf("\t\t 1.查询地点路径 \n");
printf("\t\t 2.地点信息简介\n");
printf("\t\t e.退出 \n");
printf("\t ***********************欢迎来到西安科技大学*************************\n");
printf("\t\t\t请输入您的选择:");
scanf("%c",&c);
if(c=='1'||c=='2'||c=='e')
flag=0;
}while(flag);
return c;
}
void Display(int sight1,int sight2)/*输出函数用于通过数组P[NUM][NUM]提取出从点sight1到点sight2的最短路径,从D[NUM]中输出点sight1到点sight2的最短路径的权值*/
{
int a,b,c,d,q=0;
a=sight2;
if(a!=sight1)
{
printf("\n\t从%s到%s的最短路径是",G.vex[sight1].sight,G.vex[sight2].sight);
printf("\t(最短距离为 %dm.)\n\n\t",D[a]); /*从D[NUM]中提取出sight1到sight2的最短距离的权值输出*/
printf("\t%s",G.vex[sight1].sight);
d=sight1;
for(c=0;c<NUM;++c)
{
P[a][sight1]=0;
for(b=0;b<NUM;b++)
{
if(G.arcs[d][b]<32767&&P[a][b])
{
printf("-->%s",G.vex[b].sight); /*通过P[NUM][NUM]确定sight1到sight2的最短路径*/
q=q+1;
P[a][b]=0;
d=b;
if(q%8==0) printf("\n");
}
}
}
}
}
void main()//主函数
{
int v0,v1;
char e;
char ck;
CreateMGraph(NUM);
do{ /*用do while循环确保循环至少进行一次*/
{
system("cls"); /*用system("cls")清屏使屏幕简洁*/
ck=Menu();
switch(ck) /*用switch语句确定用户选择功能*/
{
case '1':
gate: /*门函数使程序退回到gate位置*/
system("cls");
Map();
do
{
printf("\n\n\t\t\t请选择出发地序号(1~17):");
scanf("%d",&v0);
if(v0<1||v0>17)
printf("\n\n\t\t\t\t输入错误!\n");
}while(v0<1||v0>17);
do
{
printf("\t\t\t请选择目的地序号(1~17):");
scanf("%d",&v1);
if(v1<1||v1>17||v1==v0)
printf("\n\n\t\t\t\t输入错误!\n");
}while(v1<1||v1>17||v1==v0);
Dijkstra(v0);
Display(v0,v1);
printf("\n\n\t\t\t\t请按任意键继续,按e退回首页\n");
getchar();
scanf("%c",&e);
if(e=='e') /*当标识符e等于e时跳出语句*/
break;
goto gate;
case'2':
system("cls");
Info();
printf("\n\n\t\t\t\t请按回车键退回首页...\n");
getchar();
getchar();
break;
};
}while(ck!='e'); /*当标识符ck不等于e时继续循环*/
}
执行结果
存在问题分析
(1).对于输出校园平面图的功能,只简单地用printf函数输出,用一个符号组成平面图,这个方法费时费力,但还未找到更好的方法。
(2)一开始的时候没有对错误的输入作出相应提示,后来在main()函数中添加了相应的错误处理机制。