Algorithm 我们能改变迪克斯特拉吗;使用负权重的s算法?
取自维基百科的伪代码:Algorithm 我们能改变迪克斯特拉吗;使用负权重的s算法?,algorithm,dijkstra,directed-graph,single-source,Algorithm,Dijkstra,Directed Graph,Single Source,取自维基百科的伪代码: function Dijkstra(Graph, source): 2 for each vertex v in Graph: // Initializations 3 dist[v] := infinity ; // Unknown distance function from source to v 4
function Dijkstra(Graph, source):
2 for each vertex v in Graph: // Initializations
3 dist[v] := infinity ; // Unknown distance function from source to v
4 previous[v] := undefined ; // Previous node in optimal path from source
5 end for ;
6 dist[source] := 0 ; // Distance from source to source
7 Q := the set of all nodes in Graph ; // All nodes in the graph are unoptimized - thus are in Q
8 while Q is not empty: // The main loop
9 u := vertex in Q with smallest distance in dist[] ; // Start node in first case
10 if dist[u] = infinity:
11 break ; // all remaining vertices are inaccessible from source
12 end if ;
13 remove u from Q ;
14 for each neighbor v of u: // where v has not yet been removed from Q.
15 alt := dist[u] + dist_between(u, v) ;
16 if alt < dist[v]: // Relax (u,v,a)
17 dist[v] := alt ;
18 previous[v] := u ;
19 decrease-key v in Q; // Reorder v in the Queue
20 end if ;
21 end for ;
22 end while ;
23 return dist[] ;
24 end Dijkstra.
函数Dijkstra(图,源):
图中的每个顶点v有2个://初始化
3距离[v]:=无穷大;//源到v的未知距离函数
4以前的[v]:=未定义;//来自源的最佳路径中的前一个节点
5.结束通话;
6距离[来源]:=0;//源到源的距离
7 Q:=图中所有节点的集合;//图中的所有节点都是未优化的-因此在Q中
8而Q不是空的://主循环
9 u:=Q中距离最小的顶点[];//在第一种情况下启动节点
10如果距离[u]=无穷大:
11休息;//所有剩余顶点都无法从源访问
12如果结束,则结束;
13从Q中去除u;
14对于u://的每个相邻v,其中v尚未从Q中移除。
15 alt:=距离[u]+距离(u,v)之间的距离;
16如果alt
现在,在第14行中,我们看到松弛仅应用于u
的邻居,这些邻居尚未从Q
中删除。但是,如果我们也考虑从Q
中删除的u
的邻居,那么在我看来,算法确实在负权重下工作。我没有发现任何与这一说法相矛盾的实例
那么为什么Dijkstra的算法没有这样改变呢?不,正如前面所说的不可能。该算法对于负权重没有意义,除非严格限制提供的图类型 假设一个图的节点a、B、C和边的权重AB=-1、BA=0、BC=1 现在,a和C之间不再存在最短路径,您可以通过在a和B之间来回一次来创建一条较短的路径
当然,该算法仍将运行,但会给出错误的答案。只要确保不遍历任何节点或边两次,就可以确保Dijkstra的算法在负值下运行。这里所说的工作,我指的是终止。然而,结果可能不是最优的 Dijkstra的算法有一种贪婪的感觉。想象下图:
A --- 1 --- B
| |
3 -4
| |
C -- -1 --- D
如果我们想从A到B,最好的路径是A-C-D-B,但是Dijkstra的算法找到了A-B。你不能让Dijkstra的算法预测未来,因为它是一个贪婪的算法。通过预测未来,我的意思是知道以后,路径的成本可能会降低。请注意,这意味着您的修改如果应用于Dijkstra算法的一个版本,并且该版本在看到目的地后立即终止,则将无法正常工作。在您发布的版本中,除了有更有效的方法来处理负面边缘外,您的修改是有效的(请参见注释)
顺便说一句,带负值的无向图或带负循环的有向图中的最短路径根本没有意义 Dijkstra可以访问每个节点一次,因为当它选择一个新节点进行访问时,他会选择从根节点开始具有最短路径的未访问节点。因此,他可以安全地假设,通过另一个未访问的节点到该节点没有更短的路径(因为如果您知道的从a到B的最佳路径成本为2,从a到C的最佳路径成本为3,则没有机会找到从a到B的更好路径,例如a>C>B) 如果你加上负权重,你会突然打破这个假设
当然,您可以使用建议的修改,但这样您将失去只访问每个节点一次的好处;因此,与福特贝尔曼(Ford Bellman)等其他算法相比,它将失去其性能增益。您基本上有两种选择
好吧,仅仅放松修改后的Dijkstra版本中已经访问过的节点是不够的(在包含负边的图中,这会给你一个错误的答案)。此外,您需要将任何松弛的边放入容器中(例如,优先级队列或仅队列)。因此,您可以将第19行中的代码修改为:
if v is in priority queue
then decrease-key(v)
else
add v into priority queue
在这种情况下,您的算法可以工作。此外,对于正加权图,Dijkstra改进版的效率不会降低。这很容易被证明,因为这自然是一个贪婪的算法
然而,对于含有负边的图,新算法在理论分析方面可能会变得缓慢,但在实际应用中效果良好
实际上,你可以看看段定凡(1994)在中国发表的一个名为SPFA(最短路径更快算法)的算法。很多OIer(奥林匹克信息)都知道这个算法,因为它有时可能会打败Dijkstra 是的,你的