我的建议:
首先使用 Dijkstra 找到从 Source 到 Destination 的最短路径,但同时从 Source 和 Destination 步行(使用负距离数字表示您已经走过的距离目的地有多远),始终扩展最短路径距离(从源或目的地)。一旦遇到具有来自反向节点的值的节点,那么到达该节点的路径是最短的。
然后移除边,如果边不是最短路径的一部分则返回当前已知的最短路径
如果删除的边是最短路径的一部分,则再次执行搜索,已知绝对距离大于(正或负)比被删除的节点中较小的一个。将先前已知的最短路径添加到已知结果中,当从起点步行时为正,从终点走到断路段时为负。现在从该起点开始在两个方向上搜索,如果您点击了一个具有值集(正或负)的节点,或者是先前最短路径的一部分,那么您将找到新的最短路径。
这样做的主要好处是:
- 你从源和目的地都走,所以除非你的源节点在边缘,否则你在整体上走的节点更少,并且
- 您不会放弃整个搜索结果,即使删除的边是之前最短路径中的第一条边,您只需找到以最短方式重新连接的路径即可。
即使删除的节点是先前已知最短路径的一部分,每次重新计算的性能都将相当可观。
关于它是如何工作的,请看这张图:
I
/
B---E
/ / H
A D /|
\ / \ / |
C---F--G
我们想要从A
to H
,为了简单起见,让我们假设每条边都值 1(但它可以是任何东西)
我们从 A 开始:
I
/
B---E
/ / H
0 D /|
\ / \ / |
C---F--G
现在将 H 的值设置为从 0 开始:
I
/
B---E
/ / (0)
0 D / |
\ / \ / |
C---F---G
并展开:
I
/
1---E
/ / (0)
0 D / |
\ / \ / |
1---F---G
现在我们扩展下一个最小值,它将是H
:
I
/
1---E
/ / (0)
0 D / |
\ / \ / |
1---(-1)--(-1)
现在我们任意选择B
,因为它出现在 之前C
,F
或者G
(它们具有相同的绝对值):
I
/
1---2
/ / (0)
0 D / |
\ / \ / |
1---(-1)--(-1)
然后C
I
/
1---2
/ / (0)
0 2 / |
\ / \ / |
1---2 & (-1)--(-1)
现在我们有一个节点,它知道它的正值和负值,因此我们知道它到两者的距离,A
并且H
由于我们首先扩展最短节点,这一定是最短路径,因此我们可以说从A
到的最短路径H
是A->C->F->H
和成本ABS(2)+ABS(-1) = 3
现在假设我们删除了行 C->F I / 1---2 / / (0) 0 2 / | \ / \ / | 1 2 & (-1)--(-1)
然后,我们删除所有已知值,其绝对值高于 C 和 F 的较小值(在本例中为 1),留下:
I
/
1---E
/ / (0)
0 D / |
\ / \ / |
1 (-1)--(-1)
现在我们再次像以前一样展开,从B
: I / 1---2 / / (0) 0 D / | \ / \ / | 1 (-1)--(-1)
然后C
I
/
1---2
/ / (0)
0 2 / |
\ / \ / |
1 (-1)--(-1)
现在 F:
I
/
1---2
/ / (0)
0 2&(-2) / |
\ / \ / |
1 (-1)---(-1)
A
因此我们知道从to 到的最短路径H
现在是:A->C->D->F->H 和成本ABS(2)+ABS(-2) = 4
这将适用于任意数量的节点、边和边权重,如果您没有更多节点要扩展,那么您将返回“无路由”响应。
您可以通过不重置先前最短路径中节点的节点值来进一步优化它,这样做会失去简单的性质,但不会过于复杂。
在上面的示例中,它最初不会产生影响,但是如果我们随后删除链接会产生影响,因为我们会记住链中其他节点A->C
的成本(负数)C
与仅使用单面 Dijkstra 并回滚到移除边缘之前相比的好处如下所示:
I
/
1---E
/ / H
0 D /|
\ / \ / |
1 F--G
现在我们将展开B
:
I
/
1---2
/ / H
0 D /|
\ / \ / |
1 F--G
C:
I
/
1---2
/ / H
0 2 /|
\ / \ / |
1 F--G
丁:
I
/
1---2
/ / H
0 2 /|
\ / \ / |
1 3--G
E:
3
/
1---2
/ / H
0 2 /|
\ / \ / |
1 3--G
F:
3
/
1---2
/ / 4
0 2 /|
\ / \ / |
1 3--4
然后我们将确定现在的路径A->C->D->F->H
,它的成本为 4。请注意,我们需要在此处执行 5 个扩展步骤,并将其与我们需要的 3 进行比较。
随着被移除的边缘越来越靠近路径的中间,我们将通过使用双向图行走算法重新计算新路径来获得极大的节省。除非有 50 个节点挂起,但H
只有一条路径从A
到H
其中只有一条从H
到 的直接路径,A
但有 50 条边连接到A
。
鉴于您有大约 200,000 条边,可能多达 200,000 个节点,与我的示例图相比,您可能会看到可观的节省,该示例图只有 9 个节点和 11 条边。这是基于我们正在寻找具有最少节点扩展的算法的想法,因为它们可能大部分计算时间都将用于循环。