如何找到带有虫洞节点的最短路径?


25

例

这是我想通过代码执行的示例。我知道您可以使用跳转点搜索轻松地从绿色节点到红色节点,甚至A *也不会出现问题。但是,如何计算变形呢?

在图中,您可以看到,沿着蓝色路径,从绿色节点到红色节点仅需8步。蓝色路径会立即将您的位置从一个紫色节点移动到另一个紫色节点。花费2个动作的中间空间是您必须移动到的两个变形区域之间的一个点。

显然,走蓝色路径更快,因为您只需要(大约)移动一半到黄色路径,但是我该如何编程呢?

为了解决此问题,我们假设您可以使用图形周围有多个紫色“变形”,并且我们确切知道每个紫色点将变形到什么位置以及它们在图形上的位置。

有些紫色经线是双向的,而有些不是,这意味着,有时您只能从一侧进入经线,而在扭曲后不能返回。

我已经考虑了解决方案,但得出的结论是,我可以通过检查到每个变形点的距离(减去单向点)以及这些点之间的差以及与之接近的点来计算问题。 。

该程序必须弄清楚采用第二种经线比从第一条跳跃走更有益。因此,与其先移动6个点,然后进行变形,然后再步行剩余的8步(这比根本不使用经线要快),不如先移动6个点,然后再进行两次移动到第二个经线。

编辑:我意识到蓝色的路径实际上将采取12步,而不是8步,但问题仍然相同。


4
蓝色路径不应该是12(包括从最后一个紫色到红色的两个路径)吗?
BlueRaja-Danny Pflughoeft

5
蓝色实际上是12(7 + 3 + 2)个动作,对吗?
Daniel Jour

糟糕,搞砸了,谢谢大家!@DanielJour和Blue
杰夫·史密斯,

建模距离的“正确”方法是使用拓扑并将其建模为高维表面。我想知道这样的答案在这里合适吗?
Geeky I's October

Answers:


49

大多数路径查找算法是根据图形而不是网格进行定义的。在图中,两个原本遥远的节点之间的连接并不是真正的问题。

但是,您必须注意启发式。对于虫洞,两个节点之间的最小距离不再是欧氏距离,并且该距离不满足三角形不等式。这种启发式对于A *是不允许的。因此,您不能轻松使用A *。

当然,不使用启发式的路径查找算法(如Dijkstra)仍然可以使用。这更像是广度优先搜索,并且无需额外努力即可选择您的虫洞。但是,Dijkstra将访问具有启发性的A *的更多节点。(Dijkstra等效于带有*的A * heuristic(x) = 0。)

我认为,如果您使用启发式方法将所有传出的虫洞视为直接到达目标的虫洞,那么A *会起作用:启发式法可能会低估距离,但绝对不能高估它。即启发式将是:

def wormhole_heuristic(x):
  return min(euclidean_distance(x, g) for g in [goal, wormholes...])

为了获得非常精确的启发式效果,您可以(递归)添加从虫洞端点到目标或下一个虫洞的距离。即,作为预计算,您可以在(全部连接的)子图上执行路径查找,该子图上包含所有虫洞和目标,其中两个节点之间的距离为其欧几里德距离。如果虫孔的数量远小于网格上可到达的单元数,则这可能是有益的。新的启发式方法将是:

def wormhole_heuristic(x):
  direct = euclidean_distance(x, goal)
  via_wormhole = min(euclidean_distance(x, w) + wormhole_path_distance(w, goal) for w in wormholes)
  return min(direct, via_wormhole)

正如@Caleth在评论中指出的那样,这都是非常可调的,我们可以通过增加最后一个虫洞出口与目标之间的距离来改进第一个虫洞试探法,而无需通过虫洞网络进行完整路径查找。因为我们不知道哪个虫洞出口将最后使用,并且我们不能高估,所以我们必须假设出口最接近目标:

def wormhole_heuristic(x):
  direct = euclidean_distance(x, goal)
  to_next_wormhole = min(euclidean_distance(x, w) for w in wormholes)
  from_last_wormhole = min(euclidean_distance(w.exit, goal) for w in wormholes)
  via_wormhole = to_next_wormhole + from_last_wormhole
  return min(direct, via_wormhole)

10
值得一提的是Dijkstra只是A *,与dijkstra_heuristic(x) = 0
凯莱斯(Caleth)

我不明白您的意思是[* wormholes,目标],您能解释一下吗?
杰夫·史密斯,2017年

1
“到最近的虫洞出口的欧几里得距离” wormhole_path_distance比子图搜索便宜,而且比“所有出口都在目标上”要低估。
卡雷斯(Caleth)'17

3
@Caleth当然!这里有很多微调的潜力,例如我们可以决定向前看n = 3跳。子图搜索对应于所有无环虫洞跳跃的闭合。您建议n = 1跳的建议非常优雅,因为它的额外费用基本上为零:)
阿蒙(Amon)

1
为简单起见,假设只有一个虫洞(两个节点),然后可以通过复制对称平面并将两个点之间的等距线作为对称轴,将该平面1虫洞转换为2个镜像平面。现在,您有两个平面,将它们称为真实平面(不带虫孔)和虚构平面(带虫孔)。现在,我们介​​绍Z坐标。对于实际平面中的每个点,此坐标将为0,对于虚构平面中的每个点,此坐标将为dist(wormhole,point)。之后,将A *应用于3维空间。
lilezek

5

您在具有坐标的网格上有一个具有6个顶点的图形:

A ( 0,0)
B ( 4,7)
C ( 7,4)
D (10,4)
E (16,2)
F (16,0)

您可以在这些顶点上生成一个完整的图,并为每个边分配一个成本,其中,成本是MAX( ABS( x1 - x2 ), ABS( y1 - y2 ) )标准边,虫洞的成本是0。

这将为您带来成本(作为邻接矩阵):

   A  B  C  D  E  F
- -- -- -- -- -- --
A  -  7  7 10 16 16
B  7  -  0  6 12 12
C  7  0  -  3  9  9
D 10  6  3  -  0  6
E 16 12  9  0  -  2
F 16 12  9  6  2  -

如果存在单向扭曲,则仅在图形(或邻接矩阵)中创建沿该方向而不是相反的边。

然后,您可以将Dijkstra的算法优先级队列一起使用

A每个相邻的边缘开始并将其推入优先级队列:

格式:(路径:费用)

queue     = [ (A-B : 7), (A-C : 7), (A-D : 10), (A-E : 16), (A-F : 16) ]

将项目推入队列时-跟踪每个顶点的最低成本,并且仅在路径成本低于现有最低成本时才将路径推入队列。

min-costs = { A: 0, B: 7, C: 7, D: 10, E: 16, F: 16 }

从队列中删除第一项,如果其成本仍与最低成本匹配,则将由该路径及其相邻边形成的所有复合路径推回到优先级队列中(如果复合路径的成本低于现有的最低成本):

去掉: (A-B : 7)

  • 尝试(A-B-A : 14)-拒绝支付更高的费用
  • 尝试(A-B-C : 7)-拒绝相同费用
  • 尝试(A-B-D : 13)-拒绝支付更高的费用
  • 尝试(A-B-E : 19)-拒绝支付更高的费用
  • 尝试(A-B-F : 19)-拒绝支付更高的费用

去掉 (A-C : 7)

  • 尝试(A-C-A : 14)-拒绝支付更高的费用
  • 尝试(A-C-B : 7)-拒绝相同费用
  • 尝试(A-C-D : 10)-拒绝相同费用
  • 尝试(A-C-E : 16)-拒绝相同费用
  • 尝试(A-C-F : 16)-拒绝相同费用

去掉 (A-D : 10)

  • 尝试(A-D-A : 20)-拒绝支付更高的费用
  • 尝试(A-D-B : 16)-拒绝支付更高的费用
  • 尝试(A-D-C : 13)-拒绝支付更高的费用
  • 尝试(A-D-E : 10)-插入队列
  • 尝试(A-D-F : 16)-拒绝相同费用

现在,队列将如下所示:

queue     = [ (A-D-E : 10), (A-E : 16), (A-F : 16) ]
min-costs = { A: 0, B: 7, C: 7, D: 10, E: 10, F: 16 }

去掉 (A-D-E : 10)

  • 尝试(A-D-E-A : 26)-拒绝支付更高的费用
  • 尝试(A-D-E-B : 22)-拒绝支付更高的费用
  • 尝试(A-D-E-C : 19)-拒绝支付更高的费用
  • 尝试(A-D-E-D : 10)-拒绝相同费用
  • 尝试(A-D-E-F : 12)-插入队列

那么队列是:

queue     = [ (A-D-E-F : 12), (A-E : 16), (A-F : 16) ]
min-costs = { A: 0, B: 7, C: 7, D: 10, E: 10, F: 12 }

删除(A-D-E-F : 12),发现到达目的地节点的成本为12。

注:路径(A-B-C-D-E-F)(A-C-D-E-F)并且(A-D-E-F)都有12相同的最低成本。


0

设置一个包含所有顶点的矩阵,然后使用Floyd-Wallenstein-Algorithm或Bellman-Ford-Algorithm。两者都会导致矩阵之间所有点之间的路径最短。然后,您可以遍历矩阵以找到连接两个点的最短路径。(您的问题与非对称TSP相同)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.