【问题标题】:A BFS Algorithm for Weighted Graphs - To Find Shortest Distance一种用于加权图的 BFS 算法——寻找最短距离
【发布时间】:2016-07-14 19:29:11
【问题描述】:

我已经看过很多关于这个主题的帖子(即post1post2post3),但没有一个帖子提供了备份相应查询的算法。因此,我不确定接受这些帖子的答案。

在这里,我提出了一种基于 BFS 的最短路径(单源)算法,适用于非负加权图。谁能帮我理解为什么 BFS(根据以下基于 BFS 的算法)不用于此类问题(涉及加权图)!

算法:

SingleSourceShortestPath (G, w, s):
    //G is graph, w is weight function, s is source vertex
    //assume each vertex has 'col' (color), 'd' (distance), and 'p' (predecessor) 
        properties

    Initialize all vertext's color to WHITE, distance to INFINITY (or a large number
        larger than any edge's weight, and predecessor to NIL
    Q:= initialize an empty queue

    s.d=0
    s.col=GREY     //invariant, only GREY vertex goes inside the Q
    Q.enqueue(s)  //enqueue 's' to Q

    while Q is not empty
        u = Q.dequeue()   //dequeue in FIFO manner
        for each vertex v in adj[u]  //adj[u] provides adjacency list of u
             if v is WHITE or GREY       //candidate for distance update
                  if u.d + w(u,v) < v.d        //w(u,v) gives weight of the 
                                               //edge from u to v
                      v.d=u.d + w(u,v)
                      v.p=u
                      if v is WHITE
                          v.col=GREY    //invariant, only GREY in Q
                          Q.enqueue(v)
                      end-if
                  end-if
              end-if
         end-for
         u.col=BLACK  //invariant, don't update any field of BLACK vertex.
                      // i.e. 'd' field is sealed 
    end-while

运行时:据我所知是 O(|V| + |E|),包括初始化成本

如果此算法类似于任何现有算法,请告诉我

【问题讨论】:

    标签: algorithm graph shortest-path breadth-first-search weighted-graph


    【解决方案1】:

    由于伪代码是 Dijksta 的算法,它使用 FIFO 队列而不是始终根据距离排序的优先级队列。到目前为止,每个访问过的(黑色)顶点计算出的最短距离的关键不变量不一定是正确的。这就是为什么在(正)加权图中计算距离时必须使用优先队列的原因。

    您可以将您的算法用于未加权图,或者通过将每条边的权重 n 替换为 n-1 由权重为 1 的边连接的顶点来使其未加权。

    反例:

    第一个Q.enqueue(s)之后的计算状态:

    第一次迭代后的计算状态:

    作为反例的重要一点是adj[u] = adj[S] = [F, M] 而不是[M, F],因此F 首先由Q.enqueue(v) 排队

    第二次迭代后的计算状态:

    由于顶点F首先被u = Q.dequeue()出队(与使用距离优先队列时不同),本次迭代不会更新任何距离,F将变为黑色,违反不变量。

    最终迭代后的计算状态:

    【讨论】:

    • 请详细说明“这就是原因为什么不使用 BFS ......” - 不明白你在说什么!
    • 如果使用队列而不是优先队列,算法会更快,复杂度也更低。但是,对于某些加权图不会计算最短距离。优先级队列使 Dijkstra 算法能够选择下一个顶点,以确保为每个访问(黑色)顶点计算最短距离。如果改为使用 FIFO 队列,它将无法处理任意边缘权重。您甚至可以在带有圆圈的小加权图上找到反例。
    • 我已经测试了循环和自循环。我无法理解“任意”边缘权重是什么意思。请您提供一个反例!
    • 太棒了!我意识到了缺点。在将节点标记为黑色之前,我们必须确保通过最短路径之一到达它;除非我们采取一些贪婪的步骤(这是 Dijkstra 中的优先级队列),否则这是无法做到的。在您的反例中,我们将“F”标记为黑色,而不会通过任何最短路径到达它。非常漂亮。非常感谢!!
    • @TomášKratochvíla 这不是真的。您可以使用普通队列计算最短距离。它是SPFA。唯一的缺点是 SPFA 的复杂性更差。
    【解决方案2】:

    我曾经也有同样的困惑。查看SPFA 算法。当作者在 1994 年发表这个算法时,他声称它的性能比 Dijkstra 的 O(E) 复杂度更好,这是错误的。

    您可以将此算法视为 Bellman-Ford 的变体/改进。最坏情况的复杂度仍然是 O(VE),因为一个节点可能会多次从队列中添加/删除。但是对于随机稀疏图,它肯定优于原始的 Bellman-Ford,因为它跳过了许多不必要的放松步骤。

    虽然“SPFA”这个名称在学术界似乎没有得到很好的接受,但由于它的简单和易于实施,它在发布后在 ACM 学生中非常流行。性能方面的 Dijkstra 是首选。

    【讨论】:

      【解决方案3】:

      看起来您实现了 Dijkstra 的经典算法,没有堆。您正在通过每个边缘遍历矩阵,然后查看是否可以提高距离。

      【讨论】:

      • 是的,我确实丢弃了一个最小堆,发现运行时间比 Dijkstra 的要好(尽管我在没有学习 Dijkstra 算法的情况下独立完成了它。)。 Wiki 说,在运行时,对于 G 的邻接表表示,它是 Theta((|E| + |V|) log |V|) 而不是更好的 O(|E| + |V| )矿。我也不明白为什么要使用 BFS 算法。加权图几乎闻所未闻。
      • @KGhatak 你的算法不可能比 Dijkstra更好
      【解决方案4】:

      通常人们说没有边权重的时候是BFS。

      • BFS:具有恒定边权重的图。

      • Dijkstra:带有边权重的图(如果
        可以处理一些负边 它没有负循环)

      • Bellman-ford 和 SPFA:负循环图。

      您的代码是 Dijkastra 或 SPFA 变体,而不是简单的 BFS(尽管它基于基于 BFS 的算法)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多