校园导航系统之用弗洛伊德算法求加权图的最短路径
其实这个示例是在大一数据结构课程设计的时候选的题目,只不过在昨天的算法分析与设计实验课上又看到了求加权图的最短路径,忽然想起当初课程设计时为了弄懂Floyd算法而不断抓狂的过程,觉得有必要将它从邮箱的角落里释放出来,来见证自己一步步的成长。也希望能和大家一起成长。
啰嗦完了,下面进入正题吧!
1.系统需求分析:
1、设计你的学校的校园平面图,所选的景点不少于10个。以图中顶点表示校内各景点,存放景点名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。
2、为来往客人提供图中任意景点相关信息的查询。
3、为来往的客人提供图中任意景点的问路查询,即查询任意两个景点间的一条最短的简单路径。
2.系统功能模块设计
本系统分为三个模块:菜单模块 、路径查询模块、最短路径模块。得到如图所示的系统功能模块图。
3.算法思想描述将结合源码进行分析
4.源代码:
1 #include<stdio.h> 2 #include<string.h> 3 #define Num 13 4 #define Maxedge 5000 5 6 typedef struct//定义结构型 7 { 8 char name[10] ; 9 int number; 10 }vertex; 11 vertex ver[Num]; 12 int edge[Num][Num]; 13 int shortest[Num][Num]; 14 int path[Num][Num]; 15 16 void show2()//输出各地点名称 17 { 18 int i=1; 19 20 for(i=1;i<=Num;i++) 21 { 22 printf("%d---%s\t",i,ver[i].name); 23 } 24 printf("\n\n"); 25 } 26 27 void init()//初始化地点和长度 28 { 29 int i,j; 30 ver[1].number =1; 31 strcpy(ver[1].name,"文学院"); 32 ver[2].number =2; 33 strcpy(ver[2].name,"学校西门"); 34 ver[3].number =3; 35 strcpy(ver[3].name,"一号餐厅"); 36 ver[4].number =4; 37 strcpy(ver[4].name,"溜冰场"); 38 ver[5].number =5; 39 strcpy(ver[5].name,"喷泉广场"); 40 ver[6].number =6; 41 strcpy(ver[6].name,"山顶操场"); 42 ver[7].number =7; 43 strcpy(ver[7].name,"图书馆"); 44 ver[8].number =8; 45 strcpy(ver[8].name,"十号教学楼"); 46 ver[9].number =9; 47 strcpy(ver[9].name,"服务楼"); 48 ver[10].number =10; 49 strcpy(ver[10].name,"体育馆"); 50 ver[11].number =11; 51 strcpy(ver[11].name,"行政楼"); 52 ver[12].number =12; 53 strcpy(ver[12].name,"学校北门"); 54 ver[13].number =13; 55 strcpy(ver[13].name,"水房"); 56 57 for(i=1;i<=Num;i++)//初始化每天路径为最大值 58 { 59 for(j=1;j<=Num;j++) 60 { 61 edge[i][j]=Maxedge; 62 } 63 } 64 //自身到达自身为0 65 for(i=1;i<=Num;i++) 66 { 67 edge[i][i]=0; 68 } 69 //为顶点间路径赋值 70 edge[1][2]=edge[2][1]=20; 71 edge[1][5]=edge[5][1]=240; 72 edge[2][3]=edge[3][2]=50; 73 edge[2][4]=edge[4][2]=15; 74 edge[2][6]=edge[6][2]=20; 75 edge[3][4]=edge[4][3]=100; 76 edge[4][6]=edge[6][4]=70; 77 edge[4][9]=edge[9][4]=50; 78 edge[5][6]=edge[6][5]=10; 79 edge[6][10]=edge[10][6]=340; 80 edge[6][7]=edge[7][6]=40; 81 edge[7][8]=edge[8][7]=60; 82 edge[7][10]=edge[10][7]=50; 83 edge[8][9]=edge[9][8]=20; 84 edge[8][11]=edge[11][8]=140; 85 edge[9][11]=edge[11][9]=260; 86 edge[10][12]=edge[12][10]=110; 87 edge[10][13]=edge[13][10]=210; 88 } 89 90 char show3()//功能选项 91 { 92 char i; 93 printf("\t\t\t 功能菜单\n"); 94 printf("--------------------------------------------------------------------------------"); 95 printf("\t\t\t<1> 查看校园各地点代号请输入 1\n"); 96 printf("\t\t\t<2> 最短路径查询请输入 2\n"); 97 printf("\t\t\t<3> 退出系统请输入 3\n"); 98 printf("--------------------------------------------------------------------------------"); 99 printf(" \t\t^.^ 您的选择:"); 100 scanf("%s",&i); 101 return i; 102 } 103 104 void floyd()//弗洛伊德算法求两点最小权值 105 { 106 int i=1,j=1,k=1,l=1; 107 for(i=1;i<=Num;i++) 108 { 109 for(j=1;j<=Num;j++) 110 { 111 shortest[i][j]=edge[i][j]; 112 path[i][j]=0; 113 } 114 } 115 for(k=1;k<=Num;k++) 116 { 117 for(i=1;i<=Num;i++) 118 { 119 for(j=1;j<=Num;j++) 120 { 121 if(shortest[i][j]>(shortest[i][k]+shortest[k][j])) 122 { 123 shortest[i][j]=(shortest[i][k]+shortest[k][j]); 124 path[i][j]=path[j][i]=k; 125 } 126 } 127 } 128 } 129 } 130 131 void show4(int i,int j)//显示最短路径及长度。 132 { 133 int k=0,a=i,b=j; 134 if(shortest[i][j]!=Maxedge) 135 { 136 printf("从 %s 到 %s 的最短路径为:\n",ver[i].name,ver[j].name); 137 printf("%s",ver[i].name); 138 while(path[i][j]!=0) 139 { 140 k=path[i][j]; 141 while(path[i][k]!=0) 142 { 143 k=path[i][k]; 144 } 145 printf("----%s",ver[k].name); 146 i=k; 147 } 148 printf("----%s;\n",ver[j].name ); 149 printf("最短距离为:%d米。\n",shortest[a][b]); 150 } 151 else 152 printf("从 %s 不能到达 %s 。",ver[i].name ,ver[j].name ); 153 } 154 155 void shortestpath()//功能2:接受两地点并调用Floyd算法生成最短路径矩阵 156 { 157 int i=0,j=0; 158 while(1) 159 { 160 161 printf("请输入要查询的两点的编号:(以空格间隔)"); 162 scanf("%d%d",&i,&j); 163 if(i<=Num&&i>0&&j<=Num&&j>0) 164 { 165 floyd(); 166 show4(i,j); 167 return; 168 } 169 } 170 } 171 172 void main()//主程序 173 { 174 int z; 175 char i; 176 system("color 5f");//更改窗口颜色 177 init();//初始化参数 178 { 179 printf("\t\t\t ************************\n"); 180 printf("\t\t\t **河南城建学院校园导航**\n"); 181 printf("\t\t\t ************************\n\n\n\n\n"); 182 while(true)//用循环使可以多次选择选项 183 { 184 i=show3();//调用函数显示功能菜单 185 switch(i)//功能菜单选项 186 { 187 case '1':show2();break; 188 case '2':shortestpath();break; 189 case '3':{ 190 system("cls");printf("\n\n\n\n\n\n\n\n\n\t\t\t\t 谢谢您的使用\n\n\n\t\t\tO(∩_∩)O~~\t\tO(∩_∩)O~~\n\n\n\n\n\n\n\n\n"); 191 system("pause"); 192 exit(0); //退出程序 193 } 194 default :printf("输入错误!\n");break; 195 } 196 } 197 } 198 }
运行结果:
弗洛伊德算法思想:其实很简单,就是求出所有顶点两两之间的最短路径,如果该两点之间存在第三个顶点构成最短路径,则将该顶点的顶点号存入一个path[][]矩阵中,并将长度赋值给shortest[][]数组中!
其实它的核心代码只有这一段:
1 for(k=1;k<=Num;k++) 2 { 3 for(i=1;i<=Num;i++) 4 { 5 for(j=1;j<=Num;j++) 6 { 7 if(shortest[i][j]>(shortest[i][k]+shortest[k][j])) 8 { 9 shortest[i][j]=(shortest[i][k]+shortest[k][j]); 10 path[i][j]=path[j][i]=k; 11 } 12 } 13 } 14 }
事先定义出两个二维数组,shortest[i][j]中存放的是顶点i到顶点j的最短路径长度。path[i][j]的值存放的是顶点i到顶点j之间最短路径经过的顶点的值,即如果顶点i和顶点j之间存在顶点k,使i到k的距离加上k到j的距离,则将这个最短距离存入shortest[i][j]中,并将path[i][j]的值设为k,这样在寻址最短路径的时候只要根据path[i][j]中的值一步步反推出即可。