Java Floyd Warshall具有负循环。如何查找所有未定义的路径?

Java Floyd Warshall具有负循环。如何查找所有未定义的路径?,java,shortest-path,floyd-warshall,Java,Shortest Path,Floyd Warshall,我已经实现了Floyd-Warshall算法,它是有效的,但问题是我不知道如何找到所有未定义的路径。我在网上搜索过,但我只能找到如何检测图是否有负循环的答案 vector< vector <int> > floyd_warshall(vector< vector<int> > d, int n){ for(int i = 0; i < n; i++) d[i][i] = 0; for(int i = 0; i < n;

我已经实现了Floyd-Warshall算法,它是有效的,但问题是我不知道如何找到所有未定义的路径。我在网上搜索过,但我只能找到如何检测图是否有负循环的答案

vector< vector <int> > floyd_warshall(vector< vector<int> > d, int n){
    for(int i = 0; i < n; i++) d[i][i] = 0;

    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            for(int k = 0; k < n; k++){
                if(d[j][i] + d[i][k] < d[j][k] and d[j][i] != INF and d[i][k] != INF){
                    d[j][k] = d[j][i] + d[i][k];
                }
            }
        }
    }

    return d;
}
我得到了邻接矩阵:

  | 0     1     2     3     4
--|----------------------------
0 | 0    -1    -2    -2     INF
1 | INF  -2    -3    -3     INF
2 | INF  -3    -4    -4     INF
3 | INF   INF   INF   0     INF
4 | 1    -2    -3    -7     0 
我知道如果节点I是负循环的一部分,它在矩阵中的位置d[I][I]处有一个负值。所以如果我检查矩阵的对角线,我可以找到所有属于负循环的节点。如果我们看上面的例子,我们可以看到节点1和节点2是负循环的一部分。 问题是,我想找出哪些路径已经定义,哪些路径没有定义。如果可以通过负循环从A到B,那么路径的长度应该是未定义的,因为它可以是任意小的

所以问题是,如何找到所有未定义的路径

我希望算法返回矩阵:(而不是上面的一个)

其中d[i][j]=INF表示i和j之间没有路径,-INF表示i和j之间有一条任意的小路径(路径在某个地方通过一个负循环),否则d[i][j]是i和j之间的最短长度

我想测试每一条路径,但那可能太慢了。一定有一些标准的方法来解决这个问题,对吗


谢谢

我找到了解决我自己问题的办法

for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++)    // Go through all possible sources and targets

        for(int k = 0; d[i][j] != -INF && k < n; k++)
            if( d[i][k] != INF && // Is there any path from i to k?
                d[k][j] != INF && // Is there any path from k to j?
                d[k][k] < 0)      // Is k part of a negative loop?

                d[i][j] = -INF;   // If all the above are true
                                  // then the path from i to k is undefined
for(int i=0;i

我认为它应该有效,而且似乎也有效。

弗洛伊德·沃沙尔算法输出正确的结果,只要没有负数 循环存在于输入图形中。在存在负循环的情况下,计算最短(简单)路径是一个NP难问题,并且 Floyd Warshall算法不会输出正确的结果

但可以通过检查矩阵对角线中是否存在负项来检测负循环的存在。这在该算法的第8行和第9行中完成:

1. M[i, j] := ∞ ∀i 6= j
2. M[i, i] := 0 ∀i
3. M[i, j] := c((i, j)) ∀(i, j) ∈ E(G)

4. for i := 1 to n do
5.   for j := 1 to n do
6.     for k := 1 to n do
7.       if M[j, k] > M[j, i] + M[i, k] 
          then M[j, k] := M[j, i] + M[i, k]

8. for i := 1 to n do
9. if M[i, i] < 0 then return(’graph contains a negative cycle’)
1。M[i,j]:=∞ ∀i 6=j
2.M[i,i]:=0∀我
3.M[i,j]:=c((i,j))∀(i,j)∈ E(G)
4.对于i:=1到n do
5.对于j:=1到n do
6.对于k:=1到n do
7.如果M[j,k]>M[j,i]+M[i,k]
然后M[j,k]:=M[j,i]+M[i,k]
8.对于i:=1到n do
9如果M[i,i]<0,则返回('图形包含负循环')

我有一个例子可以准确地解释Floyd Warshall算法是如何工作的。本质上,Floyd-Warshall算法用于在具有正或负边权重的加权图中查找所有节点对之间的最短路径

以下算法接受邻接矩阵,其中Double.POSITIVE_∞用于指示两个节点不连接。对于每个节点,您可能还希望将权重0初始化为自身

该方法更新初始矩阵以指示所有节点对之间的最小距离。如果最短路径任意小,则答案存储为Double.NEGATIVE_∞。如果两个节点彼此无法到达,那么它仍然是双正无穷大。这个实现运行Floyd Warshall两次,如果路径长度比以前小,那么我们处于负循环

static void floydWarshall(double[][] dist) {

  int n = dist.length;

  // Compute shortest paths
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (dist[i][k] + dist[k][j] < dist[i][j])
          dist[i][j] = dist[i][k] + dist[k][j];

  // Identify negative cycles
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (dist[i][k] + dist[k][j] < dist[i][j])
          dist[i][j] = Double.NEGATIVE_INFINITY;

}
静态空隙浮华(双[]距离){
int n=距离长度;
//计算最短路径
对于(int k=0;k
我们真的需要等到三重“for”循环结束后再检查对角线吗?一旦我们发现对角线元素在第k次迭代后变成负值,我们就可以退出。这也是wiki中所说的:“应该检查算法内部for循环中路径矩阵对角线上的负数。”这真的很糟糕,如果图形包含负循环,距离可能会下溢。这个条件应该在算法的内环中进行测试。请参阅我对上述答案的评论,这也可能是下溢的。请注意,如果节点自身具有负权重的边,则上述代码不起作用,因为(在某些情况下)它无法正确传播负无穷大值。请参见我的问题:
1. M[i, j] := ∞ ∀i 6= j
2. M[i, i] := 0 ∀i
3. M[i, j] := c((i, j)) ∀(i, j) ∈ E(G)

4. for i := 1 to n do
5.   for j := 1 to n do
6.     for k := 1 to n do
7.       if M[j, k] > M[j, i] + M[i, k] 
          then M[j, k] := M[j, i] + M[i, k]

8. for i := 1 to n do
9. if M[i, i] < 0 then return(’graph contains a negative cycle’)
static void floydWarshall(double[][] dist) {

  int n = dist.length;

  // Compute shortest paths
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (dist[i][k] + dist[k][j] < dist[i][j])
          dist[i][j] = dist[i][k] + dist[k][j];

  // Identify negative cycles
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (dist[i][k] + dist[k][j] < dist[i][j])
          dist[i][j] = Double.NEGATIVE_INFINITY;

}