当前位置:   article > 正文

图论-最短路算法

图论-最短路算法

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,判断是否可以作为中间点,可以作为中间点则优化最短路。

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

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

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

更新

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

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

例题:

蓝桥1121

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

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

  1. import os
  2. import sys
  3. # 请在此输入您的代码
  4. n, m, q = map(int, input().split())
  5. INF = 10 ** 18
  6. # dp[i][j]表示i到j的最短路
  7. dp = [[INF] * (n + 1) for i in range(n + 1)] # 初始值设较大值
  8. for i in range(1, n + 1):
  9. dp[i][i] = 0 # 自己到自己的距离为0
  10. for _ in range(m):
  11. u, v, w = map(int, input().split())
  12. dp[u][v] = dp[v][u] = min(dp[u][v], w) # 双向边/无向边(可能有重边)
  13. # Floyd算法模板
  14. # dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])
  15. for k in range(1, n + 1):
  16. for i in range(1, n + 1):
  17. for j in range(1, n + 1):
  18. dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])
  19. for _ in range(q):
  20. u, v = map(int, input().split())
  21. if dp[u][v] == INF:
  22. print(-1)
  23. else:
  24. print(dp[u][v])

蓝桥8336

  1. import os
  2. import sys
  3. # 请在此输入您的代码
  4. """
  5. 翻译题意:有n个城市,m条边就是有m条路径可以流通,每个城市有自己的商品产出,可以拿去别的地方销售,
  6. 需要求出最大利润,但是商品产量ai是不变的,生产成本pi也是不变的,只有售卖单价会随着商品运输到其他
  7. 城市会改变,以及带来的运输费用(这里的运输费用有一个路径的问题,需要用最短路算出来最少支付。
  8. """
  9. n, m = map(int, input().split())
  10. # g = s - p - f(路径费用)
  11. INF = 10 ** 17
  12. a, p, s = [0] * (n + 1), [0] * (n + 1), [0] * (n + 1) # 商品的产量, 生产成本, 售卖单价
  13. f = [[INF] * (n + 1) for i in range(n + 1)] # 记录最短路(也就是最短的运输费用)
  14. g = [[0] * (n + 1) for i in range(n + 1)] # 记录利润
  15. for i in range(1, n + 1):
  16. a[i], p[i], s[i] = map(int, input().split())
  17. for _ in range(1, m + 1):
  18. u, v, w = map(int, input().split())
  19. f[u][v] = f[v][u] = min(f[u][v], w)
  20. for i in range(1, n + 1):
  21. f[i][i] = 0
  22. for k in range(1, n + 1):
  23. for i in range(1, n + 1):
  24. for j in range(1, n + 1):
  25. f[i][j] = min(f[i][k] + f[k][j], f[i][j])
  26. # g[i][j]表示城市1的物品运输到城市j可得的利润=城市j的售价-城市i的成本-运输f[i][j]
  27. for i in range(1, n + 1):
  28. for j in range(1, n + 1):
  29. g[i][j] = s[j] - p[i] - f[i][j]
  30. ans = 0
  31. for i in range(1, n + 1):
  32. # 遍历每个城市的商品
  33. now_ans = 0
  34. # 遍历移动到的城市(包括自己本身)
  35. for j in range(1, n + 1):
  36. now_ans = max(now_ans, a[i] * g[i][j])
  37. ans += now_ans # 记录每个城市的利润
  38. 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)

正在更新中...

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/606707
推荐阅读
相关标签
  

闽ICP备14008679号