路径重建-伪乘法(矩阵乘法)算法

时间:2019-06-12 15:57:43

标签: algorithm graph path-finding adjacency-matrix

上下文

我目前正在一些图形算法中进行路径重构。对于单源最短路径问题,我使用了一系列前辈来重构从一个源节点到所有其他节点的最短路径。

快速示例: [0,3,0,0]

  

从源0到目标1的最短路径将是[0,3,1],因为可以从目标节点1开始使用“父”数组向后构造路径。 1已超过3,而3已超过0。0是源。完成。


下一个算法是全对最短路径算法。最简单的例子是Floyd-Warshall算法,该算法产生一个包含所有“后继”节点的矩阵。可以在Wikipedia - Floyd Warshall上找到重构伪代码的一个好例子。 总结一下:矩阵用于存储来自一个特定源节点的每个后继。它基本上遵循与以前相同的方法,只是将每个节点作为源并向前而不是向后前进。

问题-在使用伪乘法算法的情况下如何创建后继矩阵?

让我们先看一下算法:

    for(int m = 0; m < nodeCount - 1; m++) {
        Matrix nextResultMatrix = new Matrix(nodeCount, nodeCount, Integer.MAX_VALUE);

        for(int i = 0; i < nodeCount; i++) {
            for(int j = 0; j < nodeCount; j++) {
                int value = Integer.MAX_VALUE;

                for(int k = 0; k < nodeCount; k++) {
                    value = Math.min(
                                value,
                                resultMatrix.at(i, k) + sourceMatrix.at(k, j)
                            );
                }
                nextResultMatrix.setAt(i, j, value);
            }
        }
        resultMatrix = nextResultMatrix;
    }

在每次迭代中,将计算长度为m的最短路径的矩阵。内部循环与矩阵乘法本身非常相似。在最内层的循环中,算法检查当前路径是否比从源i到k到目标j的路径短。内部k循环完成后,将设置新结果矩阵内部的值。导致问题的原因:

在Floyd-Warshall算法的情况下,更容易识别路径是否更短以及哪个节点现在是后继节点。在这种情况下,无论如何都将设置在k循环中计算出的值。是否可以在这里确定继任者?

关于可能解决方案的思考

  • 伪乘法算法为每次迭代提供一个矩阵,该矩阵表示长度为m的最短路径。可能会帮助您找到解决方案,而又不会增加-已经很糟糕的-时间复杂度,并且不必同时存储每个矩阵。
  • 我在这里对stackoverflow的评论中找到了一个有趣的想法,这可能会导致解决方案reference。从陈述中可以看出,跟踪最短路径似乎很繁重。我还没有完全理解这个想法以及如何实现这个想法。

1 个答案:

答案 0 :(得分:0)

我的解决方案

因此,在逐步完成算法并弄清楚每一步的确切含义之后,我终于能够找到解决方案。我将尝试在此处解释代码中的更改,但首先让我介绍解决方案:

for(int m = 0; m < nodeCount - 1; m++) {
    Matrix nextResultMatrix = new Matrix(nodeCount, nodeCount, Integer.MAX_VALUE);

    for(int i = 0; i < nodeCount; i++) {
        for(int j = 0; j < nodeCount; j++) {
            int value = resultMatrix.at(i, j);
            int shorterPathFoundOverNode = prevMatrix.at(i, j);

            // new shortest path from node i to j is
            // the minimum path that can be found from node i over k to j
            // k will be the node itself and every other node

            for(int k = 0; k < nodeCount; k++) {

                if(resultMatrix.at(i, k) != Graph.NO_EDGE && sourceMatrix.at(k, j) != Graph.NO_EDGE) {
                    if(value > resultMatrix.at(i, k) + sourceMatrix.at(k, j)) {

                        // update value if path is shorter
                        value = resultMatrix.at(i, k) + sourceMatrix.at(k, j);

                        shorterPathFoundOverNode = k;
                    }
                }
            }

            nextResultMatrix.setAt(i, j, value);
            prevMatrix.setAt(i, j, shorterPathFoundOverNode);
        }
    }

    resultMatrix = nextResultMatrix;
}
  • 一个非常基本但重要的想法是将Integer.MAX的j循环内的value的初始化值替换为先前找到的值,或者在第一次迭代时将其用于初始化矩阵的值(整数MAX)。这一点也很重要,因为该条件在每次迭代中都为真一次,因此之前并没有引起任何问题,但现在-由于我们在该条件内执行更多操作-很重要。

  • 有必要使用if条件替换Math.min方法,使其不仅可以设置值,还可以执行更多操作。

  • 要重建最短路径,请使用跟踪先前节点的方法。这与问题中所述的单一来源最短路径问题非常相似。当然,在这种情况下,必须使用矩阵,因为所有节点都是源节点。

  

总结一下这个想法:设置一个附加矩阵,该矩阵跟踪每个目标节点的前一个节点。当遍历k循环时,如果找到较短的路径,请保存先前的节点(重要提示:仅当它实际上比先前的路径短时)。