当前位置: 首页 > 知识库问答 >
问题:

贝尔曼-福特算法正确吗

洪雅健
2023-03-14

我一直试图通过以下资源来理解贝尔曼福特的正确实现:1

如果我们已经知道给定的加权有向图不包含一个圈(因此也没有负圈),是否遵循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;
        }

我在上述实现中遇到的第一个问题是,如果图中只有两个节点具有从源节点到目标节点的定向边,那么需要修改for的第一个循环,以0开始,而不是1,如下所示:

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

如果我做出上述改变,它仍然是正确的实现吗?

执行中的变化

如果不需要找到一个节点离src的最短距离,其中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;
        }

我想我理解了这种变化为什么有效,但是我很好奇为什么参考资料1没有提到这一点。

实现这种变体有什么缺点吗?显然,这种变体具有更好的内存需求。

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


共有1个答案

宁浩博
2023-03-14

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

 类似资料:
  • 我知道Bellman-Ford算法最多需要| V |-1次迭代才能找到最短路径,如果图不包含负权重循环。有没有办法修改Bellman-Ford算法,使其在1次迭代中找到最短路径?

  • 我有一个家庭作业来实现贝尔曼·福特的算法,并在一些图形上测试它。我实现了这个算法,在3张图中的2张上测试了它,它是有效的。但是在第三个图中,我在调用函数时没有输出。 此部分创建图形及其边。函数将顶点数和边数作为参数。 这是添加新边的函数。 下面是我对Bellman Ford算法的实现。

  • 我这里有一个更聪明的贝尔曼福特版本: 有人能想到一种图,对于这种图,该算法的时间复杂度下限为(V*E),其中V=#顶点,E=#边 我想看看这个陷阱在哪里。

  • 在具有V节点和E边的有向图中,Bellman-Ford算法将每个顶点(或者更确切地说,每个顶点的边)松弛(V-1)次。这是因为从源到任何其他节点的最短路径最多包含(V-1)条边。在第V次迭代中,如果边可以松弛,则表示存在负循环。 现在,我需要找到被这个负循环“摧毁”的其他节点。也就是说,由于从源到位于负循环中的节点的路径上有一个或多个节点,因此一些不在负循环中的节点现在与源的距离为负无穷远。 实现

  • 我正在努力改进Bellman-Ford算法的性能,我想知道改进是否正确。 我运行松弛部分不是V-1而是V次,并且我得到了一个涉及的布尔变量,如果在外循环的迭代过程中发生任何松弛,则将其设置为。如果在n.迭代中没有发生松弛,其中n 我认为这可能会改善运行时,因为有时我们不必迭代V-1次来找到最短路径,而且我们可以更早地返回,而且它也比用另一块代码检查循环更优雅。

  • 经过大量谷歌搜索,我发现大多数消息来源说迪克斯特拉算法比贝尔曼-福特算法“更有效”。但是在什么情况下Bellman-Ford算法比Dijkstra算法更好呢? 我知道“更好”是一个宽泛的说法,所以具体来说,我指的是速度和空间,如果适用的话。当然,在某些情况下,贝尔曼-福特方法比迪克斯特拉方法更好。