什么算法可以计算在地图上从点A到点B的方向?

567

地图提供商(比如谷歌或雅虎地图)是如何建议路线的呢?

它们可能有某种形式的真实世界数据,肯定包括距离,但也可能包括行驶速度、人行道存在情况、火车时间表等等。但假设数据以更简单的格式存在,例如一个非常大的有向图,边缘权重反映距离。我想能够快速计算从任意一点到另一点的方向。有时这些点会很近(在同一个城市内),而有时它们会很远(横跨全国)。

像Dijkstra算法这样的图形算法不适用于庞大的图形。幸运的是,启发式算法,如A *算法,可能有效。然而,我们的数据非常结构化,也许一种分层方法可能会起作用?(例如,在某些遥远的“关键”点之间存储预先计算的方向,以及一些本地方向。然后,两个远离的点的方向将涉及到关键点的本地方向,到另一个关键点的全局方向,以及再次的本地方向。)

实际上使用了哪些算法?

附注:此问题的动机是在在线地图方向中发现的异常。与三角不等式相反,有时候Google Maps认为使用一个中间点作为 X-Y-Z 比使用 X-Z 更长更远。但也许他们的步行路线也优化了另一个参数呢?

附注:这里又有一个违反三角不等式的例子,它表明(对我来说)他们使用某种分层方法:X-ZX-Y-Z。前者似乎使用了显眼的Sebastopol大道,即使它略微偏离了路线。

编辑:这些例子都似乎不再起作用,但在原始帖子发布时,两者都有效。


3
顺便提一句,A*算法是对Dijkstra算法的一种推广,如果有额外信息可以提供到目标点的下限距离,它可以减少需要探索的子图大小。 - Mitch Wheat
关于A*算法:是的,确实如此。幸运的是,在我们的情况下,“额外信息”可以通过使用直线距离等方式得到。当我上面说“Dijkstra”时,我指的是基本的Dijkstra算法。 - A. Rex
步行路线?不知道其他地方怎么样,但在这里(英国汉普郡),谷歌没有行人数据 - 它会将我沿着行人区周围的道路路由。它唯一有用的是更改路线所需时间的估计 :) - jTresidder
我并不特别在意这些指南是用于驾车还是步行。我只想知道它们是如何工作的!我添加步行链接的原因是因为我正在计算一种步行环绕巴黎并看到所有66个华莱士喷泉的方法。(这些地图的端点应该是华莱士喷泉。) - A. Rex
@John:我知道。我确实在尝试解决旅行商问题的一个实例。作为子程序,我向谷歌请求步行路线,并出于好玩检查了三角不等式。 - A. Rex
显示剩余3条评论
18个回答

3
说到GraphHopper,它是一个基于OpenStreetMap的快速开源路线规划器。我已经阅读了一些文献并实现了一些方法。最简单的解决方案是Dijkstra算法,而简单的改进是双向Dijkstra算法,它只探索大约一半的节点。使用双向Dijkstra算法,整个德国的路径规划只需要1秒(对于汽车模式),在C语言中可能只需要0.5秒左右;)
我创建了一个使用双向Dijkstra算法进行实际路径搜索的动画gif here。还有一些更好的方法可以使Dijkstra更快,例如使用A*算法,这是一种“目标导向的Dijkstra算法”。我也为此创建了一个gif动画
但是如何让它(更)快呢?
问题在于路径搜索需要探索两个位置之间的所有节点,而在德国就已经有数百万个节点了,这是非常昂贵的。但Dijkstra等算法的另一个痛点是这些搜索会使用大量RAM。
既有启发式解决方案,也有确切的解决方案,可以将图(道路网络)组织成分层结构,两者都有优缺点,主要解决速度和RAM问题。我在this answer中列出了其中一些。

对于GraphHopper,我决定使用收缩分层算法,因为它相对“容易”实现,并且不需要花费太长时间来准备图形。它仍然可以产生非常快速的响应时间,就像您可以在我们的在线实例GraphHopper Maps中测试的那样。例如从南非到中国东部,这导致了23000公里的距离和近14天的驾车时间,但仅在服务器上花费了约0.1秒。


使用地标的双向Dijkstra算法进行目标导向搜索比单独使用双向Dijkstra算法更有效。请参见http://www14.informatik.tu-muenchen.de/lehre/2010SS/sarntal/07_kozyncev_paper.pdf。然而,该论文没有详细说明如何计算潜在函数(有点棘手)或选择地标。 - Paul Chernoch

3

当我们不久前从圣罗莎附近的相同起点到达优胜美地国家公园的两个不同露营地时,我非常好奇所使用的启发式算法。尽管这两条路线在最后100英里(沿CA-120)收敛后又在结尾处分别扩散了几英里,但这些不同的目的地产生了完全不同的路线(通过I-580或CA-12)。这是很有重复性的。这两条路线在大约100英里的范围内相距多达50英里,但距离/时间彼此非常接近,正如你所期望的那样。

可惜我现在无法再次重现 - 算法必须已经改变了。但它让我对算法感到好奇。我唯一能推测的是,可能存在某种方向性修剪,恰好对远处看到的目的地之间微小的角度差异非常敏感,或者选择最终目的地时选择了不同的预计算段。


3
这只是我的猜测,但我认为他们可能会使用一个覆盖有定向地图的影响地图数据结构来缩小搜索范围。这将使搜索算法在所需行程较长时将路径导向主要路线。
考虑到这是一个谷歌应用程序,合理地假设很多魔法都是通过广泛的缓存完成的。 :) 我不会感到惊讶,如果缓存最常见的Google Map路线请求的前5%,允许大量(20%?50%?)的请求通过简单的查找来回答。

你有“影响地图数据结构”的好参考资料吗?谢谢! - A. Rex

3

我对此有一些想法:

1)请记住,地图代表了物理组织。存储每个交叉口的纬度/经度。您不需要检查超出您目标方向的点太多。只有当您发现自己被阻止时,才需要超越这一点。如果您存储了优秀连接的覆盖层,您甚至可以更加限制它--通常您永远不会跨越其中之一,而这种方式会远离您的最终目的地。

2)将世界分成很多由有限连接定义的区域,定义区域之间的所有连接点。找到您的起点和终点所在的区域,从您的位置到每个连接点的路线,对于之间的区域,只需在连接点之间进行映射即可。(我怀疑后者已经预先计算好了。)

请注意,区域可能比都市区域小。任何具有分割特征(例如河流)的城市都将是多个区域。


2

我在路由方面已经工作了几年,最近由于客户需求的推动而进行了一次活跃,我发现A*算法足够快;真的不需要寻找优化或更复杂的算法。在庞大的图上进行路由并不是问题。

但速度取决于是否将整个路由网络都存储在内存中。所谓路由网络是指表示路线段和路口的有向弧与节点的图。主要时间开销是创建这个路由网络的时间。根据在普通Windows笔记本电脑上对整个西班牙进行路由的粗略数据:创建网络所需时间为10-15秒;计算路线所需时间太短无法测量。

另一个重要的事情是能够重复使用网络进行多次路由计算。如果您的算法以某种方式标记了节点来记录最佳路径(当前节点的总成本和最佳弧)- 正如A*算法所必须的 - 您必须重置或清除旧信息。而不是遍历数十万个节点,使用一种生成号系统会更容易。将每个节点标记为其数据的生成号;在计算新路线时递增生成号;任何具有较早生成号的节点都已过时,其信息可以被忽略。


1

我看懂 OP 中的地图问题:

看一下指定了中间点的路径:由于那条道路不是笔直的,该路径会稍微向后走。

如果他们的算法不进行回溯,就看不到更短的路径。


有趣的想法。我在我的PPS中添加了另一个违规操作给OP。请看一下,看看是否能找到解释。 - A. Rex
将焦点A缩小到最大值的一次单击--从最大值缩小。请注意,三点路线向西、南、东走。我认为我们正在查看一种算法,除非必须通过瓶颈点,否则不喜欢返回。 - Loren Pechtel
在我的PPS示例中,将起始地址更改为“巴黎75019年弗朗德大道10号”。这消除了你所说的小回溯,但问题仍然存在。我认为主要问题是它真的想留在那条主要的大道上... - A. Rex
1
我认为在这种情况下我找到了它:用汽车行驶,时间上是合理的。它可能认为大路更快,步行路线不会限制它。 - Loren Pechtel
1
初始问题也符合这个标准,可能不是回溯引起的。 - Loren Pechtel

0
一个全对最短路径算法将计算图中所有顶点之间的最短路径。这将允许预先计算路径,而不是每次有人想要找到源和目标之间的最短路径时都需要计算路径。弗洛伊德-沃舍尔算法是一种全对最短路径算法。

-4
地图从来不考虑整个地图。 我的猜测是: 1. 根据您的位置,加载该位置上的地点和地标。 2. 当您搜索目的地时,它们会加载地图的其他部分,并将两个地方制成图表,然后应用最短路径算法。
此外,还有一种重要的技术——动态规划,我怀疑在计算最短路径时使用了这种技术。您也可以参考这个。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接