Algorithm 具有负边的Dijkstra。Don';我不理解这些示例,它们是根据CLRS伪代码工作的

Algorithm 具有负边的Dijkstra。Don';我不理解这些示例,它们是根据CLRS伪代码工作的,algorithm,graph,computer-science,dijkstra,Algorithm,Graph,Computer Science,Dijkstra,编辑2:这似乎不是来自CLRS(我假设是因为它遵循了在本Algos和DS课程中提供给我们的CLRS代码的相同格式)。 尽管如此,在本课程中,我们还是被赋予了“Dijkstra算法”的代码 我读了一遍又一遍(我认为第二篇是针对OP算法的) 看着CLRS中的伪代码(“算法简介”),我不明白Dijkstra为什么不处理那些具有负边的图的示例 在伪代码(下面)中,如果到它们的新距离小于到它们的前一距离,我们将将节点插入回堆中,因此在我看来,这些距离最终将更新为正确的距离 例如: 这里的声明是,(A,C

编辑2:这似乎不是来自CLRS(我假设是因为它遵循了在本Algos和DS课程中提供给我们的CLRS代码的相同格式)。 尽管如此,在本课程中,我们还是被赋予了“Dijkstra算法”的代码

我读了一遍又一遍(我认为第二篇是针对OP算法的)

看着CLRS中的伪代码(“算法简介”),我不明白Dijkstra为什么不处理那些具有负边的图的示例

在伪代码(下面)中,如果到它们的新距离小于到它们的前一距离,我们将
节点插入回堆中,因此在我看来,这些距离最终将更新为正确的距离

例如:

这里的声明是,(A,C)将被设置为1,并且永远不会更新到正确的距离-2

但是CLRS的伪代码说,我们首先将C和B分别放置在距离为1和2的堆上;然后我们弹出C,看不到输出边;然后我们弹出B,查看边(B,C),看到
Dist[C]>Dist[B]+w(B,C)
,将
Dist[C]
更新为-2,将C放回堆中,看到没有传出边,我们就完成了。 所以它工作得很好

这个问题的第一个答案中的例子也是如此:

答案的作者声称到C的距离不会被更新为-200,但根据这个伪代码,这是不正确的,因为我们会将B放回堆中,然后计算到C的正确最短距离

(来自CLRS的伪代码)


编辑:我知道我们假设一旦从堆中弹出一个节点,就会找到最短的距离;但是,似乎(根据CLRS),如果距离比以前计算的短,我们确实会将节点放回heapif,因此在算法运行结束时,我们应该得到正确的最短距离。

从技术上讲,实现不是Dijkstra的算法,Dijkstra描述了Dijkstra的算法(找不到更好的链接):他提到的集合
A
是已知最小路径的节点。因此,一旦你向该集合中添加一个节点,它是固定的。你知道它的最小路径,它不再参与算法的其余部分。它还谈到转移节点,因此它们不能同时位于两个集合中

这与维基百科的伪代码一致:

 1  function Dijkstra(Graph, source):
 2
 3      create vertex set Q
 4
 5      for each vertex v in Graph:             // Initialization
 6          dist[v] ← INFINITY                  // Unknown distance from source to v
 7          prev[v] ← UNDEFINED                 // Previous node in optimal path from source
 8          add v to Q                          // All nodes initially in Q (unvisited nodes)
 9
10      dist[source] ← 0                        // Distance from source to source
11      
12      while Q is not empty:
13          u ← vertex in Q with min dist[u]    // Node with the least distance will be selected first
14          remove u from Q 
15          
16          for each neighbor v of u:           // where v is still in Q.
17              alt ← dist[u] + length(u, v)
18              if alt < dist[v]:               // A shorter path to v has been found
19                  dist[v] ← alt 
20                  prev[v] ← u 
21
22      return dist[], prev[]
1函数Dijkstra(图,源):
2.
3创建顶点集Q
4.
图中的每个顶点v为5
6区[v]← 无穷远//从源到v的未知距离
7上[v]← 未定义//源的最佳路径中的上一个节点
8将v添加到Q//最初在Q中的所有节点(未访问的节点)
9
10区[来源]← 0//源到源的距离
11
12当Q不为空时:
13 u← Q中具有最小距离[u]//的顶点将首先选择距离最小的节点
14从Q中删除u
15
u://的每个相邻v为16,其中v仍在Q中。
17备选案文← 距离[u]+长度(u,v)
18如果alt
以及它的堆伪代码

但是,请注意,维基百科在回答此问题时还指出:

不必在初始化阶段用所有节点填充优先级队列,也可以将其初始化为仅包含源;然后,在if-alt 在某些情况下,这样做仍然会导致重新插入具有负值边的节点,例如在对的可接受答案中给出的示例图

因此,似乎有一些作者对此感到困惑。在这种情况下,他们应该清楚地说明,要么这个实现具有负边缘,要么它不是一个合适的Dijkstra实现

我猜原始文件可能会被解释为有点模糊。Dijkstra在其中没有提到任何负面或正面的边缘,也没有在任何其他解释之外明确指出节点在
a
集中不能更新一次。我不知道他自己是否在任何后续作品或研究中进一步澄清了事情如果剩下的只是其他人的解释问题,你会生气

所以从我的观点来看,你可以说这也是一个有效的Dijkstra's


至于为什么您可以这样实现它:因为如果我们只有正的边,那么在实践中它可能不会慢,并且因为在不需要执行额外检查或不太标准的堆操作的情况下,它的编写速度更快。

您在这里提供的伪代码似乎与CLRS第二版或第三版都不匹配另外,我刚从我的架子上取下来。你确定这是正确的伪代码吗?传统的Dijkstra实现不会在优先级队列中重新插入任何内容,而是使用减少键操作来降低现有优先级。(另外,我是你提到的链接问题的答案的作者,我很乐意与你聊天!)@templatetypedef,那太好了,谢谢!你是如何开始聊天的?这看起来更像是一个(优先)的贝尔曼·福特(Bellman Ford)queue,它可以重新插入节点,并且可以处理负边。@IVlad,我可能对CLR有错误认识。这是一门算法和DS课程,到目前为止,章节中的代码的格式与CLR中的相同,但这肯定是作为Dijkstra的算法给出的。@templatetypedef,我创建的
 1  function Dijkstra(Graph, source):
 2
 3      create vertex set Q
 4
 5      for each vertex v in Graph:             // Initialization
 6          dist[v] ← INFINITY                  // Unknown distance from source to v
 7          prev[v] ← UNDEFINED                 // Previous node in optimal path from source
 8          add v to Q                          // All nodes initially in Q (unvisited nodes)
 9
10      dist[source] ← 0                        // Distance from source to source
11      
12      while Q is not empty:
13          u ← vertex in Q with min dist[u]    // Node with the least distance will be selected first
14          remove u from Q 
15          
16          for each neighbor v of u:           // where v is still in Q.
17              alt ← dist[u] + length(u, v)
18              if alt < dist[v]:               // A shorter path to v has been found
19                  dist[v] ← alt 
20                  prev[v] ← u 
21
22      return dist[], prev[]