A*算法:Dijkstra改进算法

A*算法:Dijkstra改进算法

寻路模型

最优路规划问题处理的核心在于寻路地图的建模以及最优路规划模型。

A*算法

算法简介

A*搜索算法,俗称A星算法。这是一种在有多个节点的路径的图形平面上,求出最低成本的路径算法。A*算法是一种基于启发式搜索的算法,该算法综合了BFS(广度优先搜索)和Dijkstra算法的优点:在进行启发式搜索提高算法效率的同时,可以保证找到一条最优路径(基于评估函数)。

所谓启发式搜索,就在于当前搜索结点往下选择下一步结点时,可以通过一个启发函数来进行选择,选择代价最小的结点作为下一个搜索结点(如果代价最小的结点有很多个,不妨选择距离当前搜索点最近一次展开的搜索点进行下一步搜索)。
而DFS在展开子结点时属于盲目型搜索,也就是说,它不会选择哪个结点在下一次搜索中更优而去跳转到该结点进行下一步的搜索。而相对于另一个知名的Dijkstra 算法来说, Dijkstra算法虽然可以保证找到一条最短的路径, 但不如A*算法这样简便快速. 同时, Dijkstra的搜索深度在某些情形下也容易变得不适用.
A* 算法便是为了这些情形而出现的, 可以算是对Dijkstra算法和DFS的一种改良.

算法步骤

  • 构建评估函数 f(x)=g(x)+h(x) ,其中 g(x) 表示从起点 A 到当前点 x 的实际距离, h(x) 表示任意当前点 x 到终点 B 的估算距离(根据所采用的评估函数的不同而变化), g 值:从起点 A 到达当前方块 x 的移动量。

  • 创建open表、close表、p表,对每个点计算出h值
    – open 列表: 记录所有被考虑来寻找最短路径的方块
    – close列表: 记录不会再被考虑的方块
    – p表:记录当前节点的父节点
    – h值:采用“曼哈顿距离”(也叫“曼哈顿长”或者“城市街区距离”),它是计算出当前点x与终点B剩下的水平和垂直的方块数量(略去了障碍物或者不同陆地类型的数量)

  • 初始化open列表,即把起始点A添加到open列表

  • 递归与循环,如下:

    • 寻找open列表中f值最小的点x。 a)

    • 将x从open表中删除,加入到close列表。

    • 判断目标点B是否被添加进了close列表,若是,此时路径被找到,跳出循环。若不是,继续下述步骤。

    • 分别考虑与x相邻的8格中的每一个点T

    • 如果T不可通过或者已经在close列表中,略过。

    • 如果T可通过且不在open列表中,加入open列表。把当前格x作为T的父节点 (p(T)=x) ,记算T的f, g值。

    • 如果它已经在open列表中,用g值为参考标准,检查新的路径 A>x>T 是否更优(更低的g值意味着更优的路径)。如果是,就把T的父节点改成当前点x,并重新计算T的g和f值。将open表按f值升序排序。

    • 回到 a)
      《A*算法:Dijkstra改进算法》

格点模型

格点模型分析

格点模型我们只是进行简单地考虑,将地图上的区域标记为“可通行”与“不可通行”两部分。也就是说,我们在进行路径规划时,运动物体可在“可通行”区域任意行走,而不能触及区“不可通行”区域。我们以方块为最基本的表现方式,将一张已有的地图分成m行n列,取方块中心为一个节点,对于不可跨越的部分设计的方块,进行抹黑。我们在寻路时,黑色部分为不可达区域。这个方法很简单,只需要选择一个合适的正方形的边的大小,然后在地图上没有障碍物的地方画正方形,选取每一个正方形的中心,作为运动物体实际可以走的点。

用方块作为节点优点是简单,不过也有比较多的问题:1、如果地图很大的话,方块就会很多,这样寻路算法的节点就会大大增加,处理的时间相应地会增大。2、单位的移动只能是上下左右,最多加上斜行,总共八个方向,不够真实。3、单位的体积大小不一样的话,大单位的图像可能会覆盖到不可达部分。4、使用这种方法划分出来的网格,物体的移动其实是不连续的。有时可能看起来并不自然。5、网格数非常地多,可能需要大量的资源来计算和存储路径。

改进思路方向

地形信息是路径搜索的基础,一个算法要在室外开阔场景那种复杂的场景下提高效率,最为重要的是对地形进行有效地建模,减少不必要的节点和边,从而优化底层的搜索空间,大大提高路径搜索的速度。使用网格法,大大增加了不必要的路径搜索,也让装备移动显得很不自然。为了更好地解决以上所述的问题,导航网格应用而生。导航网格实际上就是将可行走的区域划分成多个凸多边形的集合,由于凸多边形特有的性质,作战装备在其中不管怎么走,都不会触及到多边形外的部分。使用凸多边形主要是由于它内部任意两点的连线都在其内部的性质,且每个单元在搜索中都高度独立。

导航网络算法步骤及其优缺点

导航网格,简单地说就是建立多边形网格,使用Hertel-Mehlhorn算法寻找一个覆盖整个地图的最简凸多边形集合。

  • 算法步骤如下:

    1. 我们知道任意一个三角形都是凸多边形,我们可以先通过地图的边界点和障碍物的边界点,将地图划分成很多个三角形,如下图所示。

      《A*算法:Dijkstra改进算法》)

    2. 将凸多边形之间不重要的边删除。将可以合并成新的凸多边形的相邻多边形合并,并重复这一过程,最终得到下图。

      《A*算法:Dijkstra改进算法》

    3. 我们可以在每一个网格每一条边的中点上放置路径点,将每一个网格自己边上的路径点连接起来就得到了完整的路径网络了,如下图,同上绿色的线代表画好的导航网络,蓝色的线代表可以走的路径网络。

      《A*算法:Dijkstra改进算法》

    4. 删除无关节点,细分后合并,得到最终的路径网络图。

  • 优缺点分析:
    优点:这种方法可以大大减少路径点和搜寻所需的计算量,同时也使装备的移动更加自然。在这样的路径点之间行走,我们其实可以完全无视地图上的任何障碍物。导航网络在处理动态导航需求是更为灵活。
    缺点:计算三角形和合并相邻的凸多边形需要很大的计算量。

A*算法启发函数的选取

估价价函数确定后,在检索时总是沿着 f(n) 最小的支路进行检索直到叶子节点,即找到满意的图象为止.但其一个很大的缺陷就是他们都是在一个给定的状态空间中穷举。这在状态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不预测的情况下就不可取了。在这里我们就可修正启发式搜索算法了。

启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无谓的搜索路径。可从前人的基础上修正得到一个启发评价函数,从而改进其效率。参见其他资料。

伪代码

function A*(start,goal)
     closedset := the empty set                 //已经被估算的节点集合
     openset := set containing the initial node //将要被估算的节点集合,初始只包含start
     came_from := empty map
     g_score[start] := 0                        //g(n)
     h_score[start] := heuristic_estimate_of_distance(start, goal)    //通过估计函数 估计h(start)
     f_score[start] := h_score[start]            //f(n)=h(n)+g(n),由于g(n)=0,所以省略
     while openset is not empty                 //当将被估算的节点存在时,执行循环
         x := the node in openset having the lowest f_score[] value   //在将被估计的集合中找到f(x)最小的节点
         if x = goal            //若x为终点,执行
             return reconstruct_path(came_from,goal)   //返回到x的最佳路径
         remove x from openset      //将x节点从将被估算的节点中删除
         add x to closedset      //将x节点插入已经被估算的节点
         for each y in neighbor_nodes(x)  //循环遍历与x相邻节点
             if y in closedset           //若y已被估值,跳过
                 continue
             tentative_g_score := g_score[x] + dist_between(x,y)    //从起点到节点y的距离

             if y not in openset          //若y不是将被估算的节点
                 add y to openset         //将y插入将被估算的节点中
                 tentative_is_better := true     //暂时判断为更好
             elseif tentative_g_score < g_score[y]         //如果起点到y的距离小于y的实际距离
                 tentative_is_better := true         //暂时判断为更好
             else
                 tentative_is_better := false           //否则判断为更差
             if tentative_is_better = true            //如果判断为更好
                 came_from[y] := x                  //将y设为x的子节点
                 g_score[y] := tentative_g_score    //更新y到原点的距离
                 h_score[y] := heuristic_estimate_of_distance(y, goal) //估计y到终点的距离
                 f_score[y] := g_score[y] + h_score[y]
     return failure

 function reconstruct_path(came_from,current_node)
     if came_from[current_node] is set
         p = reconstruct_path(came_from,came_from[current_node])
         return (p + current_node)
     else
         return current_node

参考外链

http://www.zhihu.com/question/29341195/answer/44493621

http://qiao.github.io/PathFinding.js/visual/

https://link.zhihu.com/?target=https%3A//harablog.wordpress.com/2011/09/07/jump-point-search/

https://link.zhihu.com/?target=http%3A//zerowidth.com/2013/05/05/jump-point-search-explained.html

http://www.redblobgames.com/pathfinding/a-star/introduction.html

http://theory.stanford.edu/~amitp/GameProgramming/MapRepresentations.html

http://www.redblobgames.com/pathfinding/grids/algorithms.html

https://www.zhihu.com/question/20298134

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/lusongno1/article/details/77231025
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞