图论-最短路算法

图论-最短路算法

码农世界 2024-05-24 后端 63 次浏览 0个评论

1. Floyd算法

  • 作用:用于求解多源最短路,可以求解出任意两点的最短路

    图论-最短路算法

    • 利用动态规划只需三重循环即可(动态规划可以把问题求解分为多个阶段)
    • 定义dp[k][i][j]表示点i到点j的路径(除去起点终点)中最大编号不超过k的情况下,点i到点j的最短距离。
    • 当加入第k个点作为i到j的中间点:dp[k]][i][j] = min(dp[k - 1]][i][j]], dp[k - 1][i][k] + dp[k - 1][k][j])

      发现可以使用滚动数组优化第一维度:

      dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])

      枚举所有k,判断是否可以作为中间点,可以作为中间点则优化最短路。

      初始化:如果无边,则dp[i][j] = INF, 有边则等于边权;dp[i][i] = 0(自己到自己是不用走的)

      为了理解更深刻,简单举个例子:

      各点之间的关系用邻接矩阵保存(下图中又两个邻接矩阵,一个是两点之间的最短距离,还有一个是两点之间的最短路中经过的节点。)

      图论-最短路算法

      图论-最短路算法

      更新

      图论-最短路算法

      每次基于之前能找到的最短路径,如果比它短就更新。

      以2号节点作为中转站是基于1号节点作为中转站的,经过n轮递推就可以得到最终答案(任意两点的最短路)

      例题:

      蓝桥1121

      图论-最短路算法

      图论-最短路算法

      为什么先遍历k,之后遍历i,j?

      因为要符合顺序,遍历完中间点后, 就要遍历邻接矩阵,进行最短距离的更新。

      import os
      import sys
      # 请在此输入您的代码
      n, m, q = map(int, input().split())
      INF = 10 ** 18
      # dp[i][j]表示i到j的最短路
      dp = [[INF] * (n + 1) for i in range(n + 1)] # 初始值设较大值
      for i in range(1, n + 1):
        dp[i][i] = 0 # 自己到自己的距离为0
      for _ in range(m):
        u, v, w = map(int, input().split())
        dp[u][v] = dp[v][u] = min(dp[u][v], w) # 双向边/无向边(可能有重边)
      # Floyd算法模板
      # dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])
      for k in range(1, n + 1):
        for i in range(1, n + 1):
          for j in range(1, n + 1):
            dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])
      for _ in range(q):
        u, v = map(int, input().split())
        if dp[u][v] == INF:
          print(-1)
        else:
          print(dp[u][v])

      蓝桥8336

      图论-最短路算法

      图论-最短路算法

      import os
      import sys
      # 请在此输入您的代码
      """
      翻译题意:有n个城市,m条边就是有m条路径可以流通,每个城市有自己的商品产出,可以拿去别的地方销售,
      需要求出最大利润,但是商品产量ai是不变的,生产成本pi也是不变的,只有售卖单价会随着商品运输到其他
      城市会改变,以及带来的运输费用(这里的运输费用有一个路径的问题,需要用最短路算出来最少支付。
      """
      n, m = map(int, input().split())
      # g = s - p - f(路径费用)
      INF = 10 ** 17
      a, p, s = [0] * (n + 1), [0] * (n + 1), [0] * (n + 1) # 商品的产量, 生产成本, 售卖单价
      f = [[INF] * (n + 1) for i in range(n + 1)] # 记录最短路(也就是最短的运输费用)
      g = [[0] * (n + 1) for i in range(n + 1)] # 记录利润
      for i in range(1, n + 1):
        a[i], p[i], s[i] = map(int, input().split())
      for _ in range(1, m + 1):
        u, v, w = map(int, input().split())
        f[u][v] = f[v][u] = min(f[u][v], w)
      for i in range(1, n + 1):
        f[i][i] = 0
      for k in range(1, n + 1):
        for i in range(1, n + 1):
          for j in range(1, n + 1):
            f[i][j] = min(f[i][k] + f[k][j], f[i][j])
      # g[i][j]表示城市1的物品运输到城市j可得的利润=城市j的售价-城市i的成本-运输f[i][j]
      for i in range(1, n + 1):
        for j in range(1, n + 1):
          g[i][j] = s[j] - p[i] - f[i][j]
      ans = 0
      for i in range(1, n + 1):
        # 遍历每个城市的商品
        now_ans = 0
        # 遍历移动到的城市(包括自己本身)
        for j in range(1, n + 1):
          now_ans = max(now_ans, a[i] * g[i][j])
        ans += now_ans # 记录每个城市的利润
      print(ans)

      总结下解题步骤:

      1. 初始化邻接矩阵(有边直接连接的直接存,没有的存INF最大值,自己到自己的路径长度为0)
      2. 遍历(k,i,j)更新i到j的最短路,通过k
      3. 依据题意更新答案

      2. Dijkstra算法

      作用:处理非负权边的单源最短路问题

      利用贪心+动态规划思想,实现从源点s出发到所有点的最短距离

      核心思想:从起点出发,每次选择距离最短的点进行”松弛”操作

      算法步骤:

      1.将起点入队列,d数组表示从起点s出发到达每个最短距离

      2.不断取出队列中距离最小的点u,进行“松弛”:

      对于从u到v,权重为w的边

      dp[v] = min(dp[v], dp[u] + w)

      正在更新中...

转载请注明来自码农世界,本文标题:《图论-最短路算法》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,63人围观)参与讨论

还没有评论,来说两句吧...

Top