Bellman-Ford算法求最短路径

先来看一张图

这题可以用动态规划来求解:

核心思想:找出递推公式,将当前问题分解成子问题,分阶段进行求解。

                  求解过程中缓存子问题的解,避免重复计算。

我们需要求v1(源点)到其他顶点的最短距离。比如求 v1 到 v4 的最短距离。

v1到v4有两条路径:①v1 -> v3 -> v4  ②v1 - > v2 -> v4

我们可以试着先求v1 -> v3的最短路径, 再求v1 -> v2 的最短路径,在求出这两个顶点的最短路径的基础上,再来看是 v3 到 v4的距离更短还是  v2 到 v4的距离更短。

先给出分析过程:

        

f(v) 用来表示从起点出发,到达v 这个顶点的距离

初始时

f(v) = 0       当 v==起点 时

f(v) = ∞       当 v!=起点 时

之后

新                 旧                所有from

f(to) = min( f(to),   f(from) + from.weight)

from     从哪来

to         到哪去

f(v4)  =  min(f(to),  f(v3) + 11)  = 20

f(v4)  =  min(20, f(v2) + 15)  = 20    从v3来的距离更短,因此未能更新更短的距离

代码实现:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class BellmanFord {
    static class Edge {
        int from;
        int to;
        int weight;

        public Edge(int from, int to, int weight) {
            this.from = from;
            this.to = to;
            this.weight = weight;
        }
    }
    /*
           
            v1  v2  v3  v4  v5  v6
            0   ∞   ∞   ∞   ∞   ∞
            0   7   9   ∞   ∞   14  第一轮
            0   7   9   20  23  11  第二轮
            0   7   9   20  20  11  第三轮
            0   7   9   20  20  11  第四轮
            0   7   9   20  20  11  第五轮

     */

    public static void main(String[] args) {
        List<Edge> edges = List.of(
                new Edge(6, 5, 9),
                new Edge(4, 5, 6),
                new Edge(1, 6, 14),
                new Edge(3, 6, 2),
                new Edge(3, 4, 11),
                new Edge(2, 4, 15),
                new Edge(1, 3, 9),
                new Edge(1, 2, 7)
        );

        //先初始化一个数组,用来存储源点到各顶点的最短距离
        int[] dp = new int[7];   //索引对应顶点编号    元素代表起点到该顶点的最短距离
        for (int i = 2; i < dp.length; i++) {
            dp[i] = Integer.MAX_VALUE;
        }
        //遍历每条边
        for (int i = 0; i < 5; i++) {
            for (Edge edge : edges) {
                if(dp[edge.from] != Integer.MAX_VALUE){   //如果不知道from的最短距离就加上边的权重,这样就没有意义
                    dp[edge.to] = Integer.min(dp[edge.to], dp[edge.from] + edge.weight);
                }
            }
        }
        print(dp);
    }

    static void print(int[] dp) {
        System.out.println(Arrays.stream(dp)
                .mapToObj(i -> i == Integer.MAX_VALUE ? "∞" : String.valueOf(i))
                .collect(Collectors.joining(",", "[", "]")));
    }
}

注意:理论上需要处理(顶点数 - 1) 轮才能得出正确结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值