Bellman-Ford算法正确与标准实现

时间:2019-07-14 20:27:59

标签: java graph-theory bellman-ford

我一直在尝试通过遵循以下资源来理解Bellman-Ford的正确实现:12

如果我们已经知道给定的加权有向图不包含循环(因此也没有负循环),是否遵循Bellman-Ford算法的正确实现?

int src = 0;
        int V = nodes.length; // 0 to n-1 nodes
        int E = edges.length;

        double[] distTo = new double[V];
        for (int i = 0; i < V; i++) {
            distTo[i] = Double.POSITIVE_INFINITY;
        }
        int[] edgeTo = new int[V];

        distTo[src] = 0.0;

        for (int i = 1; i < V - 1; i++) {

            double[] distToLocal = new double[V];
            for (int j = 0; j < V; j++) {
                distToLocal[j] = Double.POSITIVE_INFINITY;
            }

            for (int j = 0; j < E; j++) {

                int to = edges[i].to;
                int from = edges[i].from;
                int weight = edges[i].weight;

                if (distToLocal[to] > distTo[to] && distToLocal[to] > distTo[from] + weight) {
                    distToLocal[to] = distTo[from] + weight;
                    edgeTo[to] = from;
                }
              distToLocal[to] = Math.min(distToLocal[to],distTo[to]);

            }
            distTo = distToLocal;
        }

上述实现的第一个问题是,如果图中只有2个节点,且从源节点到目标节点的方向都是有向边的,则需要将第一个for循环修改为从0而不是1开始,如下所示:

for (int i = 0; i < V - 1; i++) {

如果进行上述更改,它仍然是正确的实现吗?

实施中的变化

如果没有必要从src到具有K个最大边缘(其中K为[0,V-1])的节点到int src = 0; int V = nodes.length; // 0 to n-1 nodes int E = edges.length; double[] distTo = new double[V]; for (int i = 0; i < V; i++) { distTo[i] = Double.POSITIVE_INFINITY; } int[] edgeTo = new int[V]; distTo[src] = 0.0; for (int i = 1; i < V - 1; i++) { /*double[] distToLocal = new double[V]; for (int j = 0; j < V; j++) { distToLocal[j] = Double.POSITIVE_INFINITY; }*/ for (int j = 0; j < E; j++) { int to = edges[i].to; int from = edges[i].from; int weight = edges[i].weight; if (distTo[to] > distTo[from] + weight) { distTo[to] = distTo[from] + weight; edgeTo[to] = from; } } //distTo = distToLocal; } 的最短距离,那么以下变化似乎也可以给出正确的结果。

struct foo {
    using Func = std::function<void(Args...)>;
    foo(const Func& func, Args... args)  { ... }

    struct none {};
    using A = typename std::conditional<sizeof...(Args) > 0, Func, none>::type;

    foo(const A& func) { ... };

我想我理解为什么变体有效,但是我很好奇为什么资源1没有提到这一点。

实施此变体是否有不利之处?显然,这些变体具有更好的内存需求。

注意:我知道当加权有向图中没有循环时,可以使用拓扑排序SPT算法,但是我试图理解Bellman-Ford的正确性。

1 个答案:

答案 0 :(得分:0)

Bellman-Ford算法指出,在V-1阶段,每个边缘的松弛阶段将计算出源到任何目标之间的最小距离。在您的实现中,您将运行每个阶段的V-2迭代。实际上,两个实现是相同的,您可以重用旧的距离数组。