基于Floyd算法的道路指示牌解决方案.docx
《基于Floyd算法的道路指示牌解决方案.docx》由会员分享,可在线阅读,更多相关《基于Floyd算法的道路指示牌解决方案.docx(11页珍藏版)》请在冰豆网上搜索。
基于Floyd算法的道路指示牌解决方案
基于Floyd算法的道路指示牌解决方案
绪论
中国拥有13亿人口,960万平方公里的国土面积,仅次于加拿大又略大于美国;中国公路通车里程达185万公里,铁路里程达7.43万公里。
在过去的20年里,我们在经济领域取得了巨大的成就,保持了强劲快速的增长态势。
在中国经济增长的带动下,中国公路客运交通获得了快速发展,并以每年7%~8%的速度持续增长。
与此同时,中国汽车拥有量和驾车者也都有爆发性增长;而物流运输、集装箱运输在过去的10年里增长了30%。
由此可以看出,汽车产业和交通运输在中国的迅猛增长。
为了满足不断增长的交通运输,高速公路系统的建设就迫在眉睫。
随着高速公路系统的不断完善,指示牌的作用十分重要。
指示牌为用户指明了前往各个城市的距离。
选择最短的路径,方便用户是指示牌的主要目的。
本文是基于Floyd算法,来找出设置合适的指示牌来指示用户,从而使得用户可以更加快速的到达目的地。
第一章问题模型
我们可以在每一个十字路口都设置指示牌,但这样一种方式并不是最好。
为了选择哪些城市应该在指示牌上列出,我们使用如下策略:
如果在指示牌前锋的十字路口上有一条路是到城市X的最短路,则城市X被标上指示牌。
我们假设在没对十字路口之间只有一条最短路径。
输入:
输入包括一个问题实例,描述了高速公路系统,接着是一组指示牌的位置。
高速公路系统定义为一组十字路口和一组与十字路口相连的道路。
第一行是是哪个正整数n、m、k:
n表示十字路口的数量,m表示连接各个十字路口之间道路的数量,k表示既是城市也是十字路口的数量。
接下来m行,格式是i1、i2、d,表示十字路口i1和i2直接有一条双行道,其距离为d。
接下来k行,格式是i、name,表示十字路口i是一个城市,其名字为name。
在这之后的一行,有一个正整数s,表示应防止在高速公路系统上的指示牌的数量。
接下来的s行,格式是i1、i2、d,表示从i1到i2应放置一个指示牌,从i1开始的距离是d。
对于所有的问题实例,名字的长短≤18个字符,5≤n≤30.所有的距离大于0,并精确到百分之一。
输出:
每个指示牌的输出格式如下:
name1d1
name2d2
...
namei应该左对齐,宽度为20;距离dj应四舍五入到整数。
没对“name——distance”应该按四舍五入后的距离排序;相同距离的依字幕顺序输出。
指示牌输出顺序应该与指示牌的输入顺序一致,每个指示牌之间有一个空行,你可以假设每个指示牌上至少列出一个城市。
第二章算法简介
Floyd算法又称为弗洛伊德算法,插点法,是一种用于寻找给定的加权图中顶点间最短路径的算法。
该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。
1.核心思路
通过一个图的权值矩阵求出它的每两点间的最短路径矩阵。
从图的带权邻接矩阵A=[a(i,j)]n×n开始,递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D
(1);又用同样地公式由D
(1)构造出D
(2);最后又用同样的公式由D(n-1)构造出矩阵D(n)。
矩阵D(n)的i行j列元素便是i号顶点到j号顶点的最短路径长度,称D(n)为图的距离矩阵,同时还可引入一个后继节点矩阵path来记录两点间的最短路径。
采用的是(松弛技术),对在i和j之间的所有其他点进行一次松弛。
所以时间复杂度为O(n^3);
其状态转移方程如下:
map[i,j]:
=min{map[i,k]+map[k,j],map[i,j]}
map[i,j]表示i到j的最短距离
K是穷举i,j的断点
map[n,n]初值应该为0,或者按照题目意思来做。
当然,如果这条路没有通的话,还必须特殊处理,比如没有map[i,k]这条路。
2.算法描述
a)初始化:
D[u,v]=A[u,v]
b)Fork:
=1ton
Fori:
=1ton
Forj:
=1ton
IfD[i,j]>D[i,k]+D[k,j]Then
D[I,j]:
=D[I,k]+D[k,j];
c)算法结束:
D即为所有点对的最短路径矩阵
3.算法过程
1.从任意一条单边路径开始。
所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2.对于每一对顶点u和v,看看是否存在一个顶点w使得从u到w再到v比已知的路径更短。
如果是更新它。
把图用邻接距阵G表示出来,如果从Vi到Vj有路可达,则G[i,j]=d,d表示该路的长度;否则G[i,j]=无穷大。
定义一个距阵D用来记录所插入点的信息,D[i,j]表示从Vi到Vj需要经过的点,初始化D[i,j]=j。
把各个顶点插入图中,比较插点后的距离与原来的距离,G[i,j]=min(G[i,j],G[i,k]+G[k,j]),如果G[i,j]的值变小,则D[i,j]=k。
在G中包含有两点之间最短道路的信息,而在D中则包含了最短通路径的信息。
比如,要寻找从V5到V1的路径。
根据D,假如D(5,1)=3则说明从V5到V1经过V3,路径为{V5,V3,V1},如果D(5,3)=3,说明V5与V3直接相连,如果D(3,1)=1,说明V3与V1直接相连。
4.优缺点分析
Floyd算法适用于APSP(AllPairsShortestPaths),是一种动态规划算法,稠密图效果最佳,边权可正可负。
此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法。
优点:
容易理解,可以算出任意两个节点之间的最短距离,代码编写简单
缺点:
时间复杂度比较高,不适合计算大量数据。
第三章算法分析
1.样例分析
该样例有8个十字路口,17条道路,4个城市和3个指示牌。
如图。
输出结果分别是三个指示牌上的城市列表。
例如从路口3到路口2,在距离路口3为0.45英里处立一块指示牌,表示到Bobtown还有7英里。
2.数据结构
使用邻接矩阵存储高速公路系统图:
doublegraph[MaxN][MaxN];
对于样例数据,数组graph的内容如图所示:
数组的下表与十字路口的编号一致。
0
1
2
3
4
5
6
7
0
0.00
7.12
8.34
5.33
5.36
0.00
0.00
0.00
1
7.12
0.00
4.21
0.00
0.00
0.00
6.99
10.26
2
8.34
4.21
0.00
2.74
0.00
0.00
5.04
0.00
3
5.33
0.00
2.74
0.00
4.12
7.72
5.71
0.00
4
5.36
0.00
0.00
4.12
0.00
8.94
10.29
0.00
5
0.00
0.00
0.00
7.72
8.94
0.00
5.47
8.55
6
0.00
6.99
5.04
5.71
10.29
5.47
0.00
6.01
7
0.00
10.26
0.00
0.00
0.00
8.55
6.01
0.00
数组city表示城市:
charcity[MaxN][MaxN];
对于样例数据,数组city的内容如图所示:
下标
0
1
2
3
城市
Allentown
Bobtown
Charlestown
Downville
下标是城市编号。
数组citylocation表示城市在十字路口的位置:
intcitylocation[MaxN];
对于样例数据,数组citylocation的内容如图所示:
下标
0
1
2
3
4
5
6
7
城市编号
0
1
-1
-1
-1
-1
2
3
下标是十字路口编号,值为-1时表示该路口没有城市。
3.使用Floyd方法计算所有路口之间的最短路径
采用数组path存储最短路径:
doublepath[MaxN][MaxN];
对于样例数据,数组path的内容如下:
注意表中阴影部分的单元格,其数值没有变化,表示这些路口之间没有最短路径。
4.计算最短路径经过的十字路口
采用数组shortpath存储最短路径经过的十字路口:
intshortpath[MaxN][MaxN];
0
1
2
3
4
5
6
7
0
0.00
7.12
8.07
5.33
5.36
13.05
11.04
17.05
1
7.12
0.00
4.21
6.95
11.07
12.46
6.99
10.26
2
8.07
4.21
0.00
2.74
6.86
10.46
5.04
11.05
3
5.33
6.95
2.74
0.00
4.12
7.72
5.71
11.72
4
5.36
11.07
6.86
4.12
0.00
8.94
9.83
15.84
5
13.05
12.46
10.46
7.72
8.94
0.00
5.47
8.55
6
11.04
6.99
5.04
5.71
9.83
5.47
0.00
6.01
7
17.05
10.26
11.05
11.72
15.84
8.55
6.01
0.00
对于样例数据,数组shortpath的内容如图所示:
0
1
2
3
4
5
6
7
0
-1
1
-1
-1
-1
-1
3
3
1
0
-1
-1
-1
-1
-1
6
7
2
3
1
-1
-1
-1
-1
6
6
3
0
2
-1
-1
-1
-1
6
6
4
0
3
-1
-1
-1
-1
3
3
5
3
6
-1
-1
-1
-1
6
7
6
3
1
-1
-1
-1
-1
-1
7
7
6
1
-1
-1
-1
-1
6
-1
当路口没有城市时,就不必计算,令其值为-1.表中的阴影单元与path表示对应的,表示没有最短路径通往其他城市。
单元(i,j)(i,j=0~n-1)的值为k(k≠-1,j)时,表示从路口i到路口j有最短路径,且经过路口k。
5.计算指示牌
有了shortpath表,计算只是牌列表就容易了。
如从路口i到路口k,在shortpath表中,扫描i行,其值为k时,所对应的列号j就是要列表显示的城市。
列表的数据结构如下:
structsign
{
intcityname,distance;
}sighlist[MaxN];
输出时要排序,采用标准函数qsort(),排序算法为函数cmp():
首先按里程的大小升序,在里程相等的情况下,按城市名称的字幕排序。
附:
程序源代码
#include
#include
#include
#include
constintMaxN=31;
constdoubleZero=0.0001;
//指示牌上要显示的城市列表
structsign
{
intcityName,distance;
}signList[MaxN];
charcity[MaxN][MaxN];//城市名称
//比较函数
intcmp(constvoid*a1,constvoid*b1)
{
sign*a=(structsign*)a1;
sign*b=(structsign*)b1;
//首先按里程的大小升序
if(a->distance>b->distance)return1;
//在里程相等的情况下,按城市名称的字幕顺序排序
elseif(a->distance==b->distance)
returnstrcmp(city[a->cityName],city[b->cityName]);
elsereturn-1;
}
intmain()
{
doublepath[MaxN][MaxN];//存储最短路径
doublegraph[MaxN][MaxN];//存储高速公路系统图
intshortPath[MaxN][MaxN];//存储最短路径经过的十字路口
intcityLocation[MaxN];//存储城市在十字路口的位置
intcases;//测试例数
scanf("%d",&cases);
intiCase;
for(iCase=1;iCase<=cases;iCase++)
{
inti,j,k;
inta,b;
doubled;
charname[MaxN];
intn,m,cross;//路口数量,道路数量,城市数量
scanf("%d%d%d",&n,&m,&cross);
memset(graph,0,sizeof(graph));
memset(cityLocation,255,sizeof(cityLocation));
//构造邻接矩阵
for(i=1;i<=m;i++)
{
scanf("%d%d%lf",&a,&b,&d);
graph[a][b]=graph[b][a]=d;
}
//读取城市信息
for(i=0;i{
scanf("%d",&a);
cityLocation[a]=i;
scanf("%signNum",name);
strcpy(city[i],name);
}
//使用Floyd方法计算所有路口之间的最短路径
memcpy(path,graph,sizeof(graph));
for(k=0;kfor(i=0;iif(path[i][k]>Zero)
for(j=0;jif(path[k][j]>Zero&&i!
=j)
{
d=path[i][k]+path[k][j];
if(path[i][j]d)path[i][j]=d;
}
//对角线是路口自身,清除掉
for(i=0;ipath[i][i]=0;
//计算最短路径经过的十字路口
memset(shortPath,255,sizeof(shortPath));
for(i=0;ifor(j=0;j//该路口有城市才计算
if(cityLocation[j]>=0)
for(k=0;kif(graph[i][k]>=Zero&&
fabs(path[i][j]-path[k][j]-graph[i][k]){
shortPath[i][j]=k;break;
}
if(iCase!
=1)printf("\n");
intlistNum;//指示牌上显示的城市数量
intsignNum;//指示牌的数量
scanf("%d",&signNum);
for(i=0;i{
//读取指示牌的位置信息
scanf("%d%d%lf",&a,&b,&d);
if(i!
=0)printf("\n");
//计算指示牌列表
listNum=-1;
for(j=0;jif(cityLocation[j]>=0&&shortPath[a][j]==b)
{
signList[++listNum].cityName=cityLocation[j];
signList[listNum].distance=int(path[a][j]-d+Zero+0.5);
}
//对指示牌列表排序
qsort(signList,listNum+1,sizeof(sign),&cmp);
//输出指示牌列表
for(j=0;j<=listNum;j++){
printf("%-20s",city[signList[j].cityName]);
printf("%d\n",signList[j].distance);
}
}
}
return0;
}
程序运行结果: