Floyd warshall实施似乎缺少最短路径

时间:2015-12-11 04:06:37

标签: java algorithm floyd-warshall

我正在收集弗洛伊德沃尔斯发现的最短路径的数量。对于该特定图,1 - >的最短路径。 3是5,并且有两个具有该重量的路径:1-> 4-> 2-> 3和1-> 4-> 3。

我不确定显示图表的最佳方式,因此我将使用矩阵,如果您知道更好的替代方案,请随意提出另一种方法。

 //i = infinity, no path exists initially
 //for u==v, 0
    1   2   3   4
1|  0   i   8   2
2|  i   0   2   i
3|  i   7   0   6
4|  i   1   3   0

因此,当我运行我的代码时,我从1开始计算最短路径 - > 3只是1,但我肯定有两种方式。

以下是算法的实现:

 //count[][] is initialized with a 0 if no path between [u][v], and 1 at [u][v] if there is a weight at [u][v]. 

    for (int k = 1; k <= N; k++){
        for (int i = 1; i <= N; i++){
            for (int j = 1; j <= N; j++){
                if (dist[i][j] > dist[i][k] + dist[k][j]){
                    dist[i][j] = dist[i][k] + dist[k][j];
                    counts[i][j] = 1;
                }
                else if (dist[i][j] == dist[i][k] + dist[k][j] && k != i && k != j){
                    counts[i][j] ++;                
                }
            }
        }
    }

我基本上从维基百科页面复制/粘贴代码并进行修改以保持计数。

更新:我应该提到我为所有顶点获得了正确的最短长度,并且对于所有顶点,除了[1] [3]之外我得到了正确的计数。

完整输出的打印输出:

// Shortest paths              // counts
    1    2    3    4               1    2    3    4    
1   0    3    5    2           1   1    1    1    1
2   i    0    2    8           2   0    1    1    1      
3   i    7    0    6           3   0    2    1    1 
4   i    1    3    0           4   0    1    2    1

更新:逐行逐步执行代码,当k = 4,i = 1,j = 3时,我们找到权重为5的1> 3的最短路径。

更新:阅读Floyd-Warshall算法的维基百科条目,我收集到当k = 4时,我们正在检查通过顶点{1,2,3,4}的路径。但是,在k的每次迭代中,我们只会查看[1] [3]一次。我想也许这就是问题所在。

2 个答案:

答案 0 :(得分:1)

如果您使用二维int数组来存储数据,最好将双循环更改为从0运行到N-1以避免任何潜在错误。我这样做了,结果是正确的(从1> 3的最短距离是5)。这是更新的代码和打印输出:

     //count[][] is initialized with a 0 if no path between [u][v], and 1 at [u][v] if there is a weight at [u][v]. 
    int N = 4;
    int max = 1000000;
    int[][] dist = new int[N][N];
    int[][] counts = new int[N][N];
    dist[0][0] = 0;         dist[0][1] = max;   dist[0][2] = 8;     dist[0][3] = 2;
    dist[1][0] = max;       dist[1][1] = 0;     dist[1][2] = 2;     dist[1][3] = max;
    dist[2][0] = max;       dist[2][1] = 7;     dist[2][2] = 0;     dist[2][3] = 6;
    dist[3][0] = max;       dist[3][1] = 1;     dist[3][2] = 3;     dist[3][3] = 0;
    //initialize counts
    for (int i=0; i<N; i++){
        for (int j=0; j<N; j++){
            if (dist[i][j]<max){
                counts[i][j]=1;
            }
        }
    }
    for (int k = 0; k < N; k++){
        for (int i = 0; i < N; i++){
            for (int j = 0; j < N; j++){
                if (dist[i][j] > dist[i][k] + dist[k][j]){
                    dist[i][j] = dist[i][k] + dist[k][j];
                    counts[i][j] = 1;
                }
                else if (dist[i][j] == dist[i][k] + dist[k][j] && k != i && k != j){
                    counts[i][j] ++;                
                }
            }
        }
    }
    System.out.println("i  1 2 3 4");
    for (int i=0; i<N; i++){
        System.out.print(i+1 + ": ");
        for (int j=0; j<N; j++){
            System.out.print(dist[i][j]>=max ? "i ":dist[i][j] + " ");
        }
        System.out.println();
    }
    System.out.println();
    System.out.println("i  1 2 3 4");
    for (int i=0; i<N; i++){
        System.out.print(i+1 + ": ");
        for (int j=0; j<N; j++){
            System.out.print(counts[i][j] + " ");
        }
        System.out.println();
    }

打印结果: 我1 2 3 4 1:0 3 5 2 2:i 0 2 8 3:我7 0 6 4:我1 3 0

i 1 2 3 4 1:1 1 1 1 2:0 1 1 1 3:0 2 1 1 4:0 1 2 1

答案 1 :(得分:0)

您提出的算法存在问题。不是代码。您的更新表明您已经关闭它。

您有2条最短的路径从4到3: 4-->34-->2-->3。两者的长度均为3(到k增加到4时,您的算法已经确定的长度)。 因此,在最后一次迭代过程中,您的程序会问k = 4,如果我通过4 进行操作,从1到3的路径会更短吗?然后它将决定Is 8 > 2+3-是的! 然后将最短路径数设置为1。但是,您将不再考虑从4到3的2条子路径。

这是因为Floyd Warshall一次仅考虑一个顶点(k),并检查通过该点是否缩短了路径。因此,您的程序仅计算倒数第二个不同顶点(位于目标之前的顶点)的最短路径数。它没有考虑到要达到倒数第二点的事实,您有2条最短路径可用。

以下示例应清楚说明:

  

有多少条路径可以使您到达图形中以“ V”形表示的底部(最底点)。您的程序将正确地看待基数为2的情况。但是,当询问有关形状为“ Y”的图形时,您的程序将再次查看基数,并错误地得出结论,只有一条路径通向基数。

您很幸运,您选择的测试用例遇到了这个问题!

不幸的是,我认为较小的修改不会解决该问题。这是因为Floyd Warshall算法可保证所有对之间的最短路径。不是所有对之间的所有最短路径。但是,如果您只对这种算法找到的路径感兴趣,而不是将计数初始化为1并以1递增,则初始化并以已经为您找到的顶点找到的最短子路径数递增。 (在这种情况下为2)。