在更多的应用场景中,需要用不同的算法来解决。下表总结了一些经典算法,除了贪心最优搜索之外,其他都是最优性算法,即得到的解是最短路径。表中的 m 是边的数量,n 是点的数量。

一、BFS

BFS 也是一种很不错的最短路算法。但 BFS 只适合一种场景:任意的相邻两点之间距离相等,一般把这个距离看成 1,称为“1跳”,从起点到终点的路径长度就是多少个“跳数”。在这种场景下,查找一个起点到一个终点的最有短距离,BFS 是最优的最短路径算法,计算复杂度是 O(n),n 是图上点的数量。

二、Floyd-Warshall

Floyd 算法是代码最最简单的最短路径算法,甚至比暴力的搜索更简单。它的效率不高,而且不能用于大图,但是在某些场景下也有自己的优势。Floyd算法是一种“多源”最短路算法,一次计算能得到图中每一对结点之间(多对多)的最短路径。而Dijkstra、Bellman-Ford、SPFA 算法都是“单源”最短路径算法(Single source shortest path algorithm),一次计算只能得到一个起点到其他所有点(一对多)的最短路径。可以理解为当其它算法求完某两点间最短路时,Floyd 已经求得了所有点之间的最短路。

1. Floyd算法思想

动态规划的思路:

求图上两点 i、j 之间的最短距离,可以按“从小图到全图”的步骤,在逐步扩大图的过程中计算和更新最短路。想象图中的每个点是一个灯,开始时所有灯都是灭的。然后逐个点亮灯,每点亮一个灯,就重新计算 i、j 的最短路,要求路径只能经过点亮的灯。所有灯都点亮后,计算结束。在这个过程中,点亮第 k 个灯时,能用到 1∼k−1 个亮灯的结果。

定义状态为 dp[k][i][j],i、j、k 是点的编号,范围 1∼n 。状态 dp[k][i][j] 表示在包含 1∼k 点的子图上,点对 i、j 之间的最短路。当从子图 1∼k−1 扩展到子图 1∼k 时,状态转移方程这样设计:dp[k][i][j] = min(dp[k-1][i][j], dp[k-1][i][k] + dp[k-1][k][j])

计算过程如上图所示,虚线圆圈内是包含了 1∼k−1 点的子图。方程中的 dp[k−1][i][j] 是虚线子图内的点对 i、j 的最短路;dp[k−1][i][k]+dp[k−1][k][j] 是经过 k 点的新路径的长度,即这条路径从 i 出发,先到 k,再从 k 到终点 j。比较不经过 k 的最短路径 dp[k−1][i][j] 和经过 k 的新路径,较小者就是新的 dp[k][i][j]。每次扩展一个新点 k 时,都能用到 1∼k−1 的结果,从而提高了效率。这就是动态规划的方法。

当 k 从 1 逐步扩展到 n 时,最后得到的 dp[n][i][j] 是点对 i、j 之间的最短路径长度。由于 i 和 j 是图中所有的点对,所以能得到所有点对之间的最短路。

代码分析:

for(int k=1; k<=n; k++)  //floyd的三重循环for(int i=1; i<=n; i++)for(int j=1; j<=n; j++)  // k循环在i、j循环外面dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);  //比较:不经过k、经过k
  • 初值 dp[0][i][j] ,若 i、j 是直连的,就是它们的边长;若不直连,赋值为无穷大
  • 把 dp[][][] 缩小成了 dp[][],这是用到了滚动数组,因为 dp[k][][] 只和 dp[k−1][][] 有关,所以可以省掉 k 这一维。由于 k 是动态规划的子问题的“阶段”,即 k 是从点 1 开始逐步扩大到 n 的,所以 kk 循环必须放在 i、j 循环的外面。
  • 三重循环,复杂度是 O(n^3),非常低下。

Floyd算法的寻路极为盲目,几乎“毫无章法”,这是它的效率低于其他算法的原因。但是,这种“毫无章法”,在某些情况下却有优势。

2. Floyd算法要点

1.能一次性求得所有结点之间的最短距离,这是其他最短路径算法都做不到的。

注:求所有结点之间的最短距离时,从效率上讲并不一定比其他算法强:Floyd 算法的复杂度为 O(n^3), n 是结点数量;Dijkstra 算法求所有点对之间的最短距离,复杂度是 O(mnlogn),m 是边数。不过,若图的边很稠密,m 比 n 大很多,例如在全连通图中有 m = n(n-1)/2,此时 O(mnlogn) 比 O(n^3) 还大,此时 Floyd 就有优势了。

2. 代码极其简单,是最简单的最短路算法。三重循环结束后,所有点对之间的最短路都得到了。

3. 效率低下,计算复杂度是 O(n^3), 只能用于 n < 300 的小规模的图。

4. 存图用邻接矩阵 dp[][] 是最好最合理的,不用更省空间的邻接表。

注:这个因为 Floyd 算法计算的结果是所有点对之间的最短路,本身就需要 n×n 的空间,用矩阵存储最合适。

5. 可判断负圈

注:负圈:若图中有权值为负的边,某个经过这个负边的环路,所有边长相加的总长度也是负数,这就是负圈。在这个负圈上每绕一圈,总长度就更小,从而陷入在负圈上兜圈子的死循环。Floyd 算法很容易判断负圈,只要在算法运行过程出现任意一个 dp[i][i]<0 就说明有负圈。因为 dp[i][i] 是从 i 出发,经过其他中转点绕一圈回到自己的最短路径,如果小于零,就存在负圈。

3. Floyd 算法的应用场景

1. 图的规模小,n<300。计算复杂度 O(n^3) 限制了图的规模。不需要用其他算法,其他算法的代码更长,写起来麻烦。

2. 问题的解决和中转点有关。这是 Floyd 算法的核心思想,算法用 DP 方法遍历中转点来计算最短路。

3. 路径在“兜圈子”,一个点可能多次经过。这是 Floyd 算法的特长,其他路径算法都不行。

4. 可能多次询问不同点对之间的最短路。这是 Floyd 算法的优势。

4. 经典题目练习

点击->题目分析及参考代码

公园观景

题目描述

小明喜欢观景,于是今天他来到了公园。

已知公园有 N 个景点,景点和景点之间一共有 M 条道路。小明有 Q 个观景计划,每个计划包含一个起点 st 和一个终点 ed,表示他想从 st 去到 ed。但是小明的体力有限,对于每个计划他想走最少的路完成,你可以帮帮他吗?

输入描述

输入第一行包含三个正整数 N,M,Q

第 2 到 M + 1 行每行包含三个正整数 u,v,w 表示 uv 之间存在一条距离为 w 的路。

第 M+2 到 M + Q-1 行每行包含两个正整数 st,ed,其含义如题所述。

(1 ≤ ≤ 400,1 ≤ ≤ N×(N−1)​/2,≤ 10^3,1 ≤ u,v,st,e≤ n,1 ≤ ≤ 10^9)

输出描述

输出共 Q 行,对应输入数据中的查询。

若无法从 st 到达 ed 则输出 -1。

样例输入

3 3 3
1 2 1
1 3 5
2 3 2
1 2
1 3
2 3

样例输出

1
3
2

打印路径

题目描述

王国有 N 个城市,任意两城市间有直通的路或没有路。每条路有过路费,并且经过每个城市都要交税。定义从 a 城到 b 城,其花费为路径长度之和,再加上除 a 与 b 外所有城市的过路费之和。

现给定若干对城市,请你打印它们之间最小花费的路径。如果有多条路经符合,则输出字典序最小的路径。

输入描述

第一行给定一个 N 表示城市的数量,若 N=0 表示结束。

接下来 N 行,第 i 行有 N 个数,​  表示第 i 个城市到第 j 个城市的直通路过路费,若  ​= −1 表示没有直通路。

接下来一行有 N 个数,第 i 个数表示第 i 个城市的税。再后面有很多行,每行有两个数,表示起点和终点城市,若两个数是 -1,结束。

输出描述

对给定的每两个城市,输出最便宜的路径经过哪些点,以及最少费用。

样例输入

3
0 2 -1
2 0 5
-1 5 0
1 2 3
1 3
2 3
-1 -1
0

样例输出

From 1 to 3 :
Path: 1-->2-->3
Total cost : 9From 2 to 3 :
Path: 2-->3
Total cost : 5

指数移动

题目描述

一个图有 n 个点,有 m 个边连接这些点,边长都是 1 千米。小明的移动能力很奇怪,他一秒能跑 2^t 千米,t 是任意自然整数。问小明从点 1 到点 n,最少需要几秒。

输入描述

第一行两个整数 n,m,表示点的个数和边的个数。

接下来 m 行每行两个数字 a,b,表示一条 a 到 b 的边。

(1 ≤ ≤ 50,1 ≤ ≤ 10000,最优路径长度 ≤ 2^32。)

输出描述

输出一个整数,表示答案。

样例输入

5 5
1 2
2 2
3 4
3 5
2 3

样例输出

1

如有错误和需要改进完善之处,欢迎大家纠正指教。

最短路算法——Floyd-Warshall相关推荐

  1. 算法小讲堂之最短路算法(Floyd+bellman+SPFA+Dijkstra)

    前言 如果你对图论相关知识一点也没有,那么建议您先去了解这些知识:https://acmer.blog.csdn.net/article/details/122310835,然后就可以快乐的学习最短路 ...

  2. 最短路算法----floyd算法

    目录 1:Floyd算法的介绍 2:Floyd算法的代码展现 3:Floyd算法举例 1:Floyd算法的介绍 Floyd算法是属于最短路算法的一种,它是用来求多源最短路径,换句话来说就是求任意两个点 ...

  3. 最短路算法floyd

    内容: 对n个点(n<=450),已知他们的边,也就是相邻关系,求任意两个点的最短距离. 代码: for(int k=1; k<=n; k++)//k写在外面for(int i=1; i& ...

  4. 坐在马桶上看算法:只有五行的Floyd最短路算法

    坐在马桶上看算法:只有五行的Floyd最短路算法 此算法由Robert W. Floyd(罗伯特·弗洛伊德)于1962年发表在"Communications of the ACM" ...

  5. 【啊哈!算法】算法6:只有五行的Floyd最短路算法

            暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程.         上图中有 ...

  6. 最短路算法详解(Dijkstra/SPFA/Floyd)

    转自:http://blog.csdn.net/murmured/article/details/19281031 一.Dijkstra Dijkstra单源最短路算法,即计算从起点出发到每个点的最短 ...

  7. 【算法】只有五行的Floyd最短路算法

     暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有4个城市8条公路,公路上的数字 ...

  8. C++floyd warshall算法求最短路径(附完整源码)

    C++floyd warshall算法求最短路径 floyd warshall算法求最短路径的完整源码(定义,实现,main函数测试) floyd warshall算法求最短路径的完整源码(定义,实现 ...

  9. 最短路最基本算法———Floyd算法

    关于floyd算法 算法简介 实现思想 核心代码 后记 一.floyd简介 引自百度百科 在计算机科学中,Floyd-Warshall算法是一种在具有正或负边缘权重(但没有负周期)的加权图中找到最短路 ...

  10. Floyd Warshall算法

    Description: 描述: This is a very popular interview problem to find all pair shortest paths in any gra ...

最新文章

  1. 第十章: 数据模型高级进阶
  2. Antd组件中单选框、复选框自定义样式的优雅实现
  3. MFC中的GDI绘图
  4. 整体管理6个过程及相关重点
  5. linux下大文件裁剪,Linux系统裁剪(2)之Linux系统裁剪
  6. javaIO流-File类及其方法
  7. C#实现10进制转2进制
  8. Java web 实战项目案例
  9. 思维导图的了解和使用
  10. 有哪些毕设免费查重和降重的网站
  11. 滨江机器人餐厅_滨江机器人的视觉效果好吗?
  12. MATLAB聚类分析源代码
  13. linux wine 原理,wine的工作原理与自动运行PE程序
  14. Android涉及到的设计模式
  15. 计算机专业国考录取比例,国考招录中,报考人数近18万,有3类专业成功几率高...
  16. 【收集】个人认为比较实用的手机软件
  17. android中出现javax.net.ssl.SSLPeerUnverifiedException的解决方案
  18. 拓嘉辰丰:拼多多活动结束,怎样避免流量大跌尴尬期
  19. 小飞学习Docker之使用容器
  20. 牛客的AI模拟面试(1)

热门文章

  1. xposed框架定位修改怎么用_硬核!教你三种方法,实现微信自定义修改地区!
  2. 动态规划(Dynamic Programming)算法与LC实例的理解
  3. 终于找到淘口令的坑了
  4. 51单片机矩阵按键模块
  5. android sony 镜像,解释如何使用Sony TV DLNA屏幕镜像功能
  6. 基于C#的图书管理系统
  7. redis与数据库同步的解决方案
  8. matlab 自写iradon,matlab的radon变换
  9. MDESIGN-设计标准化系统
  10. Linux服务器如何修改登录用户的密码