【问题标题】:"Bidirectional Dijkstra" by NetworkXNetworkX 的“双向 Dijkstra”
【发布时间】:2016-06-17 05:44:10
【问题描述】:

我刚刚阅读了 Dijkstra 算法的 NetworkX 实现,用于使用双向搜索(this)的最短路径。这个方法的终点是什么?

【问题讨论】:

  • 在代码中的一条评论中写道:# if we have scanned v in both directions we are done # we have now discovered the shortest path。但是我们有一个反例this post
  • 对于它的价值 - 在你给出的例子中 networkx 给出了正确的路径。
  • @Joel 感谢您的准确回答。您能否提供更多详细信息,例如您的测试程序或它的跟踪。
  • 在我的示例中,dijkstra 找到 A 然后 D 然后 C,因为 4+1 小于 6(A 然后 C)。我不知道 NetworkX 是如何处理这个问题的。
  • @moksef - 我已经更新了我的答案。我今天学到了一些东西!好问题。

标签: python algorithm graph networkx shortest-path


【解决方案1】:

我将基于networkx的实现。

双向 Dijkstra 在两个方向遇到相同节点时会停止 - 但它在该点返回的路径可能不是通过该节点。它正在执行额外的计算来跟踪最短路径的最佳候选者。

我的解释将基于您的评论(this answer

考虑这个简单的图(带有节点 A、B、C、D、E)。该图的边及其权重为:"A->B:1","A->C:6","A->D:4","A->E:10","D-> C:3","C->E:1"。当我在两边对该图使用 Dijkstra 算法时:向前它在 A 和 D 之后找到 B,在向后它在 E 和 D 之后找到 C。在这一点上,两个集合都有相同的顶点和一个交点。这是终止点还是必须继续?因为这个答案(A->D->C->E)是不正确的。

供参考,这是图表:

当我在反例中的(无向)网络上运行 networkx 的双向 dijkstra 时,您声称该评论:"A->B:1","A->C:6","A->D:4","A->E:10","D->C:3","C->E:1":它给了我:(7, ['A', 'C', 'E']),而不是 A-D-C-E

问题在于对它在停止之前在做什么的误解。它在查找节点方面完全符合您的期望,但是在执行此操作时,会发生额外的处理来查找最短路径。当它从两个方向到达D 时,它已经收集了一些其他可能更短的“候选”路径。不能保证仅仅因为节点D 从两个方向到达,最终成为最短路径的一部分。相反,在从两个方向都到达一个节点时,当前候选最短路径比它继续运行时找到的任何候选路径都要短。

算法从两个空簇开始,每个簇与AE相关联

{}          {}

它会在每个周围建立“集群”。它首先将A 放入与A 关联的集群中

{A:0}          {}

现在它检查A 是否已经在E 周围的集群中(当前为空)。它不是。接下来,它查看A 的每个邻居,并检查它们是否在E 周围的集群中。他们不是。然后它将所有这些邻居放入A 的即将到来的邻居的堆(如有序列表)中,按来自A 的路径长度排序。将此称为A 的“边缘”

clusters                 .....        fringes

{A:0}          {}        .....        A:[(B,1), (D,4), (C,6), (E,10)]
                                      E:[]

现在它检查E。对于E,它会做对称的事情。将E 放入其集群中。检查E 是否不在A 周围的集群中。然后检查它的所有邻居,看看A 周围的集群中是否有任何邻居(它们不是)。然后创建E 的边缘。

clusters                                  fringes
{A:0}          {E:0}        .....        A:[(B,1), (D,4), (C,6), (E,10)]
                                         E:[(C,1), (A,10)]

现在它回到A。它从列表中获取B 并将其添加到A 周围的集群中。它检查B 的任何邻居是否在E 周围的集群中(没有要考虑的邻居)。所以我们有:

clusters                                  fringes
{A:0, B:1}        {E:0}     .....        A:[(D,4), (C,6), (E,10)]
                                         E:[(C,1), (A,10)]

回到E:我们将C添加到E的集群中,并检查C的任何邻居是否在A的集群中。你知道吗,有A。所以我们有一个候选最短路径 A-C-E,距离为 7。我们会坚持下去。我们将D 添加到E 的边缘(距离为4,因为它是1+3)。我们有:

clusters                                  fringes
{A:0, B:1}        {E:0, C:1}     .....   A:[(D,4), (C,6), (E,10)]
                                         E:[(D,4), (A,10)]

candidate path: A-C-E, length 7

回到A:我们从它的边缘得到下一个东西,D。我们将它添加到大约A 的集群中,并注意它的邻居C 在大约E 的集群中。所以我们有一个新的候选路径,A-D-C-E,但它的长度大于 7,所以我们丢弃它。

clusters                                  fringes
{A:0, B:1, D:4}     {E:0, C:1}     .....   A:[(C,6), (E,10)]
                                           E:[(D,4), (A,10)]

candidate path: A-C-E, length 7

现在我们回到E。我们看D。它位于A 周围的集群中。我们可以肯定,我们将遇到的任何未来候选路径的长度至少与我们刚刚追踪的A-D-C-E 路径一样大(这种说法不一定很明显,但它是这种方法的关键)。所以我们可以停下来。我们返回之前找到的候选路径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-26
    • 1970-01-01
    • 2017-12-06
    • 2019-04-01
    • 2017-06-20
    • 2016-02-27
    • 2021-02-14
    • 1970-01-01
    相关资源
    最近更新 更多