贝尔曼 - 福特的负循环

时间:2018-06-16 09:21:06

标签: algorithm graph-theory shortest-path bellman-ford

在具有V节点和E边的有向图中,Bellman-Ford算法放宽每个顶点(或者更确切地说,是每个顶点的边缘)(V-1)次。这是因为从源到任何其他节点的最短路径最多包含(V-1)个边缘。在第V次迭代中,如果边缘可以放宽,则表明存在负循环。

现在,我需要通过这个负循环找到其他节点“毁了”。也就是说,一些不在负循环上的节点现在与源的负无穷远距离,因为从源到节点的路径上的一个或多个节点处于负循环中。

实现这一目标的一种方法是运行Bellman-Ford并注意负循环上的节点。然后,从这些节点运行DFS / BFS以标记其他节点。

然而,为什么我们不能在没有求助于DFS / BFS的情况下运行Bellman-Ford 2 *(V-1)次来检测这样的节点?如果我的理解是正确的,放松所有顶点2 *(V - 1)次应该允许负循环将它们的值“传播”到所有其他连接的节点。

其他详细信息:我在解决此在线问题时遇到了这种情况:https://open.kattis.com/problems/shortestpath3

我使用的Java代码(以及此处未显示的BFS / DFS)如下:

  // Relax all vertices n - 1 times.
  // And relax one more time to find negative cycles
  for (int vv = 1; vv <= n; vv++) {
    // Relax each vertex
    for (int v = 0; v < n; v++) {
      // For each edge
      if (distTo[v] != (int) 1e9) {
        for (int i = 0; i < adjList[v].size(); i++) {
          int dest = adjList[v].get(i).fst;
          int wt = adjList[v].get(i).snd;

          if (distTo[v] + wt < distTo[dest]) {
            distTo[dest] = distTo[v] + wt;

            if (vv == n) {
              isInfinite[v] = true;
              isInfinite[dest] = true;
            }
          }
        }
      }
    }
  }

2 个答案:

答案 0 :(得分:3)

考虑使用N=4, M=5的图形:

A -> B weight 1000
A -> C weight 1000
C -> D weight -1
D -> C weight -1
D -> B weight 1000

让A作为我们的来源,而B作为我们的目的地。

现在显然存在一个负循环(C <-> D)。但是,无论我们运行该算法N次,2N次或什至3N次,从A到B的最短路径仍然是1000。由于负周期每次使用都只会使距离减小一小部分,因此不会推动我们期望的其他节点。

一种解决方案是,一旦识别出影响节点的循环,就将该距离标记为负无穷大。这样,负循环将“优先于”通过其他节点的其他最短路径。

您真诚的,
一个在这个问题上花了很多时间的编码人员。

答案 1 :(得分:1)

在经典情况下,所有节点&#34; on&#34;负长度周期与源有任意小的距离。 因此,在v-1之后的每次迭代中,从源到这样的节点的路径变得更小。 该任务要求您为所有此类节点返回-infinity。

您可以使用Bellman-Ford算法的修改版本将所有此类节点的距离标记为-infinity并将其运行v-1次以使-infinity传播到连接到该循环的所有其他节点。但是,与仅从循环中的节点运行DFS或BFS相比,这需要花费很多额外的时间。