我的建议:
首先使用Dijkstra算法从源点到目标点找到最短路径,但同时从源点和目标点开始遍历(使用负距离数表示已经走了多少距离离目标还有多远),始终扩展距离更短的节点(无论是从源节点还是目标节点)。一旦遇到一个节点,它与反向节点之间存在连边,则到达该节点的路径就是最短路径。
然后移除这条边,如果该边不是最短路径的一部分,则返回当前已知的最短路径
如果被移除的边是最短路径的一部分,则再次进行搜索,已知绝对距离大于被移除的两个节点之间较小距离(正数或负数)。将以前已知的最短路径作为正数添加到结果中,当从起点行走时为正数,从终点往回走时为负数,直到达到断开的部分。现在从该起点向两个方向搜索,如果遇到一个设置了值(正数或负数)的节点,或者曾经是以前最短路径的一部分,则找到了新的最短路径。
这样做的主要好处是:
- 您可以同时从源点和目标点开始遍历,因此除非您的源节点位于边界上,否则总共会遍历更少的节点;
- 即使删除的边是先前最短路径中的第一条边,您也不必放弃整个搜索结果,只需找到重新连接的最短路径即可。
即使被移除的节点是已知的最短路径的一部分,与每次进行蛮力计算相比,性能都会明显提高。
关于其工作原理,请考虑以下图形:
I
/
B---E
/ / H
A D /|
\ / \ / |
C---F--G
我们希望从
A
到达
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。然后我们删除所有已知绝对值高于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到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
D:
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个边相比,您可能会看到相当大的节省。这基于我们正在寻找具有最少节点扩展的算法,因为它们很可能会花费大量计算时间进行循环。