Answers:
回想一下,在Dijkstra的算法中,将某个顶点标记为“封闭”(且不在开放集内)-该算法找到了到达该顶点的最短路径,并且不再需要再次开发此节点-它假定为此开发了路径路径是最短的。
但是负数-可能不正确。例如:
A
/ \
/ \
/ \
5 2
/ \
B--(-10)-->C
V={A,B,C} ; E = {(A,C,2), (A,B,5), (B,C,-10)}
来自A的Dijkstra首先开发C,后来找不到 A->B->C
编辑更深入的解释:
请注意,这很重要,因为在每个松弛步骤中,算法都假定“关闭”节点的“成本”确实很小,因此接下来要选择的节点也是最小的。
它的想法是:如果我们有一个开放的顶点,这样它的成本是最小的-通过向任何顶点添加任何正数 -最小值将永远不会改变。
如果没有对正数的限制-上述假设是不正确的。
由于我们“知道”每个“闭合”的顶点都是最小的-我们可以安全地执行松弛步骤-而无需“回头”。如果确实需要“回头看”,Bellman-Ford会提供类似递归(DP)的解决方案。
A->B
将5和A->C
2。然后B->C
将-5
。因此,的价值C
将-5
与Bellman-ford相同。这怎么不能给出正确的答案?
A
值为0的节点。然后,它将在值最小的节点上查找B
为5且C
为2。最小值为C
,因此它将C
以值2 关闭并且永远不会向后看稍后B
关闭,它无法修改的值C
,因为它已“关闭”。
A -> B -> C
?它将首先将C
的距离更新为2,然后将的距离更新B
为5。假设您的图形中没有的传出边C
,则访问时我们什么也不做C
(其距离仍然为2)。然后,我们访问D
的相邻节点,唯一的相邻节点是C
,其新距离为-5。请注意,在Dijkstra的算法中,我们还跟踪从中到达(并更新)节点C
的父节点,然后从进行跟踪,您将获得父节点B
,然后A
得到,结果是正确的。我想念什么?
当我在解释中提到Dijkstra算法时,我将讨论下面实现的Dijkstra算法。
因此,从最初分配给每个顶点的值(从源到顶点的距离)开始,
我们首先提取Q = [A,B,C]中具有最小值(即A)的顶点,此后Q = [B,C]。请注意,A与B和C有直边,而且它们都在Q中,因此我们更新了这两个值,
现在我们将C提取为(2 <5),现在Q = [B]。请注意,C没有连接,因此line16
循环不会运行。
最后,我们提取B,然后。注意,B指向C,但是Q中不存在C,因此我们也不再在中输入for循环line16
,
所以我们最终得出距离为
请注意,这是怎么回事,因为从A到C的最短距离是5 + -10 = -5 。
因此,对于该图,Dijkstra的算法错误地计算了从A到C的距离。
之所以会发生这种情况,是因为Dijkstra的算法未尝试找到到达已从Q提取的顶点的较短路径。
什么是line16
循环做的是顶点ü,并说:“嘿看起来我们可以去v通过从源头ü,是(ALT或替代)距离任何优于现行DIST [V]我们得到了什么?如果是这样,您更新dist [v] “
注意,在line16
他们检查所有邻居v(即有向边存在从u到v)的ü它们仍然在Q中。在line14
他们从问:所以删除走访笔记,如果X是拜访邻居ü,路径是没有考虑从源头上可能更短的方式v。
在上面的示例中,C是B的访问邻居,因此未考虑该路径,从而使当前最短路径保持不变。
如果边缘权重都是正数,这实际上很有用,因为这样我们就不会浪费时间考虑不可能更短的路径。
因此,我说运行此算法时,如果x是从y之前的Q中提取的,则不可能找到路径- 较短。让我用一个例子来解释一下
由于y刚刚被提取并且x在其自身之前被提取,因此dist [y]> dist [x],因为否则y将在x之前被提取。(line 13
最短距离优先)
正如我们已经假定的,边缘权重为正,即length(x,y)> 0。因此,通过y的替代距离(alt)始终要确保更大,即dist [y] + length(x,y)> dist [x]。因此,即使y被视为x的路径,dist [x]的值也不会被更新,因此我们得出结论,仅考虑仍在Q中的y的邻居是有意义的(请注意中的注释)line16
但是,这取决于我们对边的正长度的假设,如果length(u,v)<0,则取决于边的负值,我们可以在进行比较后替换dist [x]line18
。
因此,如果在删除所有顶点v之前删除x,则我们进行的所有dist [x]计算都将是错误的-从而使x是v的相邻点,并且将它们连接到负边。
因为这些v个顶点中的每一个都是从源到x的潜在“更好”路径上的倒数第二个顶点,因此Dijkstra算法将其丢弃。
因此,在我上面给出的示例中,错误是因为在删除B之前先删除C。而那个C却是B的邻居,而且边缘不好!
需要说明的是,B和C是A的邻居。B有一个邻居C,而C没有邻居。length(a,b)是顶点a和b之间的边长。
Dijkstra算法的正确性:
在算法的任何步骤中,我们都有2组顶点。集A由我们计算出最短路径的顶点组成。集B由其余顶点组成。
归纳假设:在每个步骤中,我们将假定所有先前的迭代都是正确的。
归纳步骤:将顶点V添加到集合A并将距离设置为dist [V]时,必须证明该距离是最佳的。如果这不是最佳选择,那么到顶点V的路径必须较短。
假设这条其他路径通过某个顶点X。
现在,由于dist [V] <= dist [X],因此到V的任何其他路径都将是至少dist [V]长度,除非该图具有负边长。
因此,为了使dijkstra的算法起作用,边缘权重必须为非负数。
在下图上尝试Dijkstra的算法,假设A
是源节点,以查看发生了什么:
A->B
将1
和A->C
意志100
。然后B->D
会2
。然后C->D
会-4900
。因此,的价值D
将-4900
与Bellman-ford相同。这怎么不能给出正确的答案?
A->B
会1
和A->C
会100
。然后B
进行探索并设置B->D
为2
。然后探索D,因为当前它具有返回源的最短路径?我是否正确地说,如果B->D
是100
,C
将首先进行探索?我了解人们在您以外的所有其他例子。