复杂地图找最短路径的算法有:1、Dijkstra 算法;2、Bellman-Ford 算法;3、Floyd 算法;4、SPFA 算法;5、A* 算法。Dijkstra 算法是一个基于「贪心」、「广度优先搜索」、「动态规划」求一个图中一个点到其他所有点的最短路径的算法。
一、复杂地图找最短路径算法是什么
1、Dijkstra 算法
Dijkstra 算法,是由荷兰计算机科学家 Edsger Wybe Dijkstra 在1956年发现的算法,戴克斯特拉算法使用类似广度优先搜索的方法解决赋权图的单源最短路径问题。Dijkstra 算法原始版本仅适用于找到两个顶点之间的最短路径,后来更常见的变体固定了一个顶点作为源结点然后找到该顶点到图中所有其它结点的最短路径,产生一个最短路径树。本算法每次取出未访问结点中距离最小的,用该结点更新其他结点的距离。需要注意的是绝大多数的Dijkstra 算法不能有效处理带有负权边的图。
基本思想:
- 通过Dijkstra计算图G中的最短路径时,需要指定一个起点D(即从顶点D开始计算)。
- 此外,引进两个数组S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点D的距离)。
- 初始时,数组S中只有起点D;数组U中是除起点D之外的顶点,并且数组U中记录各顶点到起点D的距离。如果顶点与起点D不相邻,距离为无穷大。
- 然后,从数组U中找出路径最短的顶点K,并将其加入到数组S中;同时,从数组U中移除顶点K。接着,更新数组U中的各顶点到起点D的距离。
- 重复第4步操作,直到遍历完所有顶点。
2、Bellman-Ford 算法
美国应用数学家Richard Bellman(理查德.贝尔曼, 动态规划的提出者)于1958年发表了该算法。此外Lester Ford在1956年也发表了该算法。因此这个算法叫做Bellman-Ford算法。其实EdwardF. Moore在1957年也发表了同样的算法,所以这个算法也称为Bellman-Ford-Moore算法。Bellman-ford 算法比dijkstra算法更具普遍性,因为它对边没有要求,可以处理负权边与负权回路。缺点是时间复杂度过高,高达O(VE), V为顶点数,E为边数。
基本思想:
- 初始化:将除起点s外所有顶点的距离数组置无穷大 d[v] = INF, d[s] = 0
- 迭代:遍历图中的每条边,对边的两个顶点分别进行一次松弛操作,直到没有点能被再次松弛
- 判断负圈:如果迭代超过V-1次,则存在负圈
3、Floyd 算法
Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。简单的来说,算法的主要思想是动态规划(dp),而求最短路径需要不断松弛(熟悉spfa算法的可能熟悉松弛)。
基本思想:
- 邻接矩阵dist储存路径,同时最终状态代表点点的最短路径。如果没有直接相连的两点那么默认为一个很大的值(不要溢出)!而自己的长度为0。
- 从第1个到第n个点依次加入图中。每个点加入进行试探是否有路径长度被更改。
- 而上述试探具体方法为遍历图中每一个点(i,j双重循环),判断每一个点对距离是否因为加入的点而发生最小距离变化。如果发生改变,那么两点(i,j)距离就更改。
- 重复上述直到最后插点试探完成。
4、SPFA 算法
SPFA算法是求解单源最短路径问题的一种算法,由理查德·贝尔曼(Richard Bellman)和莱斯特·福特创立的。有时候这种算法也被称为 Moore-Bellman-Ford 算法,因为 Edward F. Moore 也为这个算法的发展做出了贡献。它的原理是对图进行V-1次松弛操作,得到所有可能的最短路径。其优于迪科斯彻算法的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高,高达 O(VE)。但算法可以进行若干种优化,提高了效率。
基本思想:
- 用dis数组记录点到有向图的任意一点距离,初始化起点距离为0,其余点均为INF,起点入队。
- 判断该点是否存在。(未存在就入队,标记)
- 队首出队,并将该点标记为没有访问过,方便下次入队。
- 遍历以对首为起点的有向边(t,i),如果dis[i]>dis[t]+w(t,i),则更新dis[i]。
- 如果i不在队列中,则入队标记,一直到循环为空。
5、A* 算法
A*(念做:A Star)算法是一种很常用的路径查找和图形遍历算法。它有较好的性能和准确度。本文在讲解算法的同时也会提供Python语言的代码实现,并会借助matplotlib库动态的展示算法的运算过程。A*算法最初发表于1968年,由Stanford研究院的Peter Hart, Nils Nilsson以及Bertram Raphael发表。它可以被认为是Dijkstra算法的扩展。由于借助启发函数的引导,A*算法通常拥有更好的性能。
基本思想:
- 初始化开集(open set)和闭集(closed set),将起点加入开集。
- 每次从开集中选取 f 值(f(n) = g(n) + h(n),其中 g(n) 是起点到节点 n 的实际代价,h(n) 是节点 n 到终点的估计代价)最小的节点 n,并将该节点从开集中移除,加入闭集。
- 对于节点 n 的每个相邻节点 m,进行以下处理:如果 m 在闭集中,则跳过;如果 m 不在开集中,将 m 加入开集,并将 n 设为 m 的前驱节点,同时更新 m 的 f 值和 g 值(g(m) = g(n) + d(n, m),其中 d(n, m) 是节点 n 到节点 m 的代价);如果 m 已经在开集中,判断 g(m) 是否更小,如果更小则更新 m 的 f 值、g 值和前驱节点。
- 重复步骤 2 和 3,直到终点被加入到闭集中或开集为空。
- 如果终点被加入到闭集中,则找到了最短路径,反向遍历前驱节点即可。如果开集为空,则不存在可行路径。
二、最短路径问题
最短路径问题是图论研究中的一个经典算法问题,旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。
1、具体形式
- 确定起点的最短路径问题:即已知起始结点,求最短路径的问题。适合使用Dijkstra算法。
- 确定终点的最短路径问题:与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。
- 确定起点终点的最短路径问题:即已知起点和终点,求两结点之间的最短路径。
- 全局最短路径问题:求图中所有的最短路径。适合使用Floyd-Warshall算法。
2、应用领域
- 城市规划:城市规划中需要规划各种交通设施的建设以及道路的布局,这就需要考虑最短路径问题以确定优异的布局方案。
- 物流运输:在物流运输中,需要根据货物的重量、体积、运费等因素,计算出从仓库到目的地的最短路径,以提高运输效率和降低成本。
- 网络路由:在计算机网络中,路由器需要快速准确地计算数据包的传输路径,因此需要使用最短路径算法来确定优异路由方案。
- 机器人导航:在机器人导航中,机器人需要根据环境地图和当前位置,计算出能够避开障碍物、同时最短路径到达目标点的路线。
- 游戏设计:在游戏设计中,需要根据场景中各个元素之间的关系,计算出玩家能够到达目标点的最短路径,从而提供更好的游戏体验。
延伸阅读1:经典算法问题
- 八皇后问题:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
- “Missionaries & Cannibals” 传道士与野人问题:三个传教士和三个食人族来到一条河边。有一艘可坐两个人的划艇。如果食人族的数量超过了在河两岸的传教士,传教士就会被吃掉。
- Tower of Hanio 汉诺塔问题:源于印度一个古老传说,大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?