“最优路径”的自动实现

      相信大家都用过百度地图、高德地图之类的吧,凡是与地理信息系统相关的APP,必不可少的一个功能那就是“最优路径”的自动实现了。就是说用户只需要指定自己的起点和目的地,那么系统会自动帮用户挑选出一条最优路径出来,并将其显示在地图上。是不是很神奇呢?!

      嗷,在进入正题之前先让yogurt来吐槽一下下!说到这个程序,那真是自己给自己挖的一个坑啊!自己一年前写的东西,本来想着来修改修改的,于是便把路网的权值初始化为MAX这一步给取消掉了,还以为自己之前是多此一举,后来调试了好久~~~~(>_<)~~~~看了半天终于搞明白了!这个MAX对构建最短路径表的时候判断是否更新尤为重要啊!想想心都碎了!(大家等会儿看程序的时候可以关注一下,如果把初始化为MAX去掉,会造成什么严重的后果)

      所以下面我得讲得仔细一点,要不然一不小心你们也看不懂了(如果你说“yogurt,我轻轻松松就看懂了好吧!”  噫--那我收回前面说的话。毕竟我智商好像最近有点不够用了!急需你们借一点给我,哈哈哈!)

      步入正题,我建议大家在看这篇程序之前可以先去了解一下Prim算法的内容,我的最短路径就是根据这个算法来实现的。如果你懒得去看了,那也没关系,因为我接下来会简单地把他算法的精髓挖出来给你们看一下。至于路网的存储构建方法,大家可以参考一下我的上一篇博客《构建带权路网》,在这里就不再重复介绍了。

==================================此处是精髓===================================233

假设有7个点,Prim算法就是很机智的把他们分为两部分,一部分是已经计算好最短路径的源(我们称为圈1),另一部分是未计算过的(我们称为圈2)。当然啦一开始的时候,所有的点都在圈2里面。每个点都有三个参数,分别是distance(该点到起点的最短距离),source_point(该点上一步经过的点),s(记录该点是否已经计算过即是否已经入圈1),以下简称d、p、s。

第一步:给定一个起点,我们修改好起点的参数之后就将起点从圈2放到圈1里面去。接下来更新圈2里面的每个点到圈1里面起点的距离(不与起点直接相连的点的d是MAX很大的一个值,意思就是不可直达)。更新好之后,找到distance最小的点把它放到圈1里面去,它也很荣幸升级成了圈1中的一员啦!

第二步:好,每放一个点进入圈1,我们都要修改这个点的参数(d、p、s),接着还需要更新圈2的点的d,为什么呢?因为对于与刚进入圈1 的点(比如p1点)直接相邻的点,说从起点经过p1之后再到这个点的距离比直接从起点过来的距离更近呢!所以这次的更新过程每个点都是需要判断是否需要更新的。更新完之后,也是找到distance最小的点把它放到圈1里面去,就这样圈1里面又添了一名家族成员。

然后重复第二步,一个一个的把圈2的点全部升级到圈1里面去,直到所有的点都在圈1里面了,那么从起点到每一个点的最短距离也就出来了。

===============================yogurt的小科普课堂结束===============================

让我今天纠结了这么久的当然不会就仅仅是一个Prim算法这样子啦!下面放大招了,代码呈上来!还添加了一个命令要求,比如你说“yogurt,我想从点0去点3,但是途中我一定要先去一趟点4呢!”嗷!你可真是神烦!”不过可难不倒聪明机智美丽善良的yogurt,哈哈哈哈哈哈哈~~

  1 #include"stdafx.h"
  2 #include"Graph.h"
  3 #include"targetver.h"
  4 #include<stdlib.h>
  5 #define MAX_VERTEX_NUM 6
  6 #define MAX 10000
  7 
  8 typedef struct Vertex
  9 {
 10     int  x, y;
 11 }vertex;
 12 
 13 typedef struct Graph
 14 {
 15     vertex ver[MAX_VERTEX_NUM];
 16     int weight[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
 17     int vexnum;
 18     int arcnum;
 19 }graph;
 20 
 21 typedef  struct Shortest
 22 {
 23     int distance, sourcepoint, s;
 24 }shortest;  //最短路径表
 25 
 26 graph createroad(char * filename);
 27 void printroad(graph G);
 28 void findminroad(graph G, char x, shortest a[]);
 29 
 30 void main()
 31 {
 32     graph G = createroad("information.txt");  //读入路网的信息
 33     printroad(G);  //输出路网结构
 34 
 35     int x, y, w;  //起点x,终点y,指定必过点w
 36     int i, j;
 37 
 38     printf("Please enter the start:");
 39     scanf("%d", &x);
 40 
 41     shortest a[MAX_VERTEX_NUM];
 42     findminroad(G, x, a);  //最短路径表a
 43 
 44     printf("\nPlease enter the end:");
 45     scanf("%d", &y);
 46     int save_y = y;
 47 
 48     //-----------------------------------------------------------------------变色显示由x->y
 49     do {
 50         //x-->y的路径
 51         setPenColor(RED);
 52         moveTo(G.ver[a[y].sourcepoint].x, G.ver[a[y].sourcepoint].y);
 53         lineTo(G.ver[y].x, G.ver[y].y);
 54         y = a[y].sourcepoint;
 55     } while (a[y].sourcepoint != MAX);
 56 
 57     printf("\nPlease enter the point which must be passed:");
 58     scanf("%d", &w);
 59 
 60 
 61     //画从w-->y的最小路径
 62     shortest b[MAX_VERTEX_NUM];
 63     findminroad(G, w, b);  //找到指定点w为起点的最短路径表b
 64 
 65     //-----------------------------------------------------------------------变色显示由x->w->y
 66     
 67     do{
 68         //x->w的路径
 69         setPenColor(GREEN);
 70         moveTo(G.ver[a[w].sourcepoint].x, G.ver[a[w].sourcepoint].y);
 71         lineTo(G.ver[w].x, G.ver[w].y);
 72         w = a[w].sourcepoint;
 73     } while (a[w].sourcepoint != MAX);
 74 
 75     y = save_y;
 76     do{
 77         ////w->y的路径
 78         setPenColor(BLUE);
 79         moveTo(G.ver[b[y].sourcepoint].x, G.ver[b[y].sourcepoint].y);
 80         lineTo(G.ver[y].x, G.ver[y].y);
 81         y = b[y].sourcepoint;
 82     } while (b[y].sourcepoint != MAX);  
 83 
 84     return;
 85 }
 86 
 87 graph createroad(char *filename)
 88 {
 89     graph g;
 90     FILE* fp = fopen("information.txt", "r");
 91     if (fp)
 92     {
 93         fscanf(fp, "%d", &g.vexnum);  //顶点数
 94         for (int i = 0; i < g.vexnum; i++)  //G的数组元素初始化
 95         {
 96             g.ver[i].x = 0;
 97             g.ver[i].y = 0;
 98             for (int j = 0; j < MAX_VERTEX_NUM; j++)
 99                 g.weight[i][j] = MAX;
100         }  //初始化
101         fscanf(fp, "%d", &g.arcnum);  //边数
102         for (int i = 0; i <g.vexnum; i++)  //顶点数组
103             fscanf(fp, "%d,%d", &g.ver[i].x, &g.ver[i].y);
104 
105         int v1, v2, w;
106         for (int i = 0; i < g.arcnum; i++)  //构造邻接矩阵
107         {
108             fscanf(fp, "%d %d %d", &v1, &v2, &w);
109             g.weight[v1][v2] = w;
110             g.weight[v2][v1] = w;
111         }
112     }fclose(fp);
113     return g;
114 }
115 
116 void printroad(graph G)
117 {
118     setOrig(0, 0);
119     setPenColor(WHITE);
120     for (int i = 0; i < G.vexnum; ++i)
121     {
122         drawRectangle(G.ver[i].x, G.ver[i].y);
123 
124         char label[10];
125         sprintf(label, "%d", i);
126 
127         drawText(G.ver[i].x, G.ver[i].y, label);
128 
129         for (int j = 0; j <G.vexnum; ++j)
130         {
131             if (G.weight[i][j]!=MAX)
132             {
133                 moveTo(G.ver[i].x, G.ver[i].y);
134                 lineTo(G.ver[j].x, G.ver[j].y);
135             }
136         }
137     }
138 }
139 
140 void findminroad(graph G, char x, shortest a[])
141 {
142     //初始化a[]
143     for (int i = 0; i < G.vexnum; i++)
144         a[i].s = 0;
145 
146     int m = x, min = MAX, q = G.vexnum;
147     a[m].s = 1;  //标识已入源
148     a[m].sourcepoint = MAX;
149 
150     int j;
151     int t;
152 
153     for (int i = 0; i < G.vexnum; i++)
154     {
155         if (a[i].s == 0)  //在未入源中进行
156         {
157             a[i].distance = G.weight[m][i];
158             a[i].sourcepoint = m;
159             if (a[i].distance !=MAX && a[i].distance < min)  //标识相邻且最小距离点
160             {
161                 j = i;    //j记录最小距离点
162                 min = a[i].distance;
163             }
164         }
165     }//第二个点入源,不需要更新distance
166 
167     do{
168         m = j;  //j入源
169         a[m].s = 1;  //标识已入源
170 
171         min = MAX;  //每次都必须为min赋值为MAX
172         for (int i = 0; i < G.vexnum; i++)
173         {
174             if (a[i].s == 0 && G.weight[m][i]>0)  //在未入源且与新加入点相邻的点中进行
175             {
176                 t = a[m].distance + G.weight[m][i];  //t判断是否需要更新
177                 if (t < a[i].distance)  //需要更新
178                 {
179                     a[i].distance = t;
180                     a[i].sourcepoint = m;
181                 }
182                 if (a[i].distance < min)  //标识最小距离点
183                 {
184                     j = i;
185                     min = a[i].distance;  //min更新
186                 }
187             }  
188         }//distance更新完毕
189         q--;
190     } while (q>1); //执行G.vexnum-1次
191     return;
192 }
View Code

接下来就是yogurt给你们见证奇迹的时刻啦~~

(这里解释一下:路网原本都是用白色画的哈,红色的是直接从点0到达点3的路径;蓝色的路径是从点0出发,经过点4之后再到达点3的最优路径。

哇塞,是不是很神奇,原来那些地图APP上的最优路径就是这样实现的!不过,也许yogurt的代码有的地方写得太啰嗦了点,欢迎大家批评指正哈!

 

转载于:https://www.cnblogs.com/to-sunshine/p/5997285.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值