路径规划可以分为广度优先,和深度优先。广度优先是队列,先进先出。深度优先是堆栈,先进后出。
广度优先和深度优先都可以找到最优解,但是需要更多的计算资源,因为它们会访问更多的栅格才会找到一条到达目标点的路径。后面主要讲广度优先。
此时引入贪心策略改进广度优先。
广度优先在从队列里压入数据的时候并没有很明确的指向性,一般都是自己定一个简单的规则,例如顺时针或者逆时针压入当前点的邻点。然后取出数据是先进先出。Dijstar,A*算法都对单纯的广度优先进行了改进。
引入代价函数g(n),该函数表示起点到当前点的代价 。
Dijstar 算法就是使用了g(n)代价函数:
-
将起点放入一个队列,如果起点在障碍物中,或者终点在障碍物中,break.。否则设置它的g(Xs) = 0,其它位置的栅格g(X)= infinite 无穷大。
-
从队列中弹出起点,获取它的邻点。并计算邻点的代价g(n):
如果邻点已经被扩展过,并且此时计算 的代价值小于之前保存的代价值。那么更新该邻点的代价值。
如果邻点没有被扩展过,则计算代价值。并把零点放入一个队列。 -
如果邻点没有发现终点则继续循环2
Dijstar算法可以得到最优解。虽然Dijstar算法在一定程度上改善了广度优先算法的访问栅格比较多的问题,但是依旧会访问很多的栅格。
为了使搜索的栅格带有一定的方向性,有人就使用了贪心策略,此时就变为了A算法,添加代价函数h(n),表示当前点到目标点的距离,因此总的代价函数就变为了:f(n) = g(n) + h(n)。因此在弹出节点时依据f(n),算法大致和Dijstar差不多,在第二步的时候如果g(n)更新了,那么f(n)也要跟着改变。A得到的路径是次优解。
概念:admissible Heuristics
选择贪心函数是的一个准则 h(n) <= h(n)*,贪心函数计算的距离要小于等于实际的距离。
• Priority queue in C++
• std::priority_queue
• std::make_heap
• std::multimap
改进A*的方法
选择合适的贪心函数
二维平面的紧贪心函数,在二维平面使用这个贪心函数,可以进一步减少扩展的栅格。
Tie Breaker(打断对称点)
例如有些栅格的f(n)值相等,因此就会遍历这两个点的邻点,如果通过某个方法可以比较这两个点则只需要遍历较小的栅格的邻点。
mininum cost of step :一个栅格的代价一般等于1
expected maximum path cost: 整个代价地图最长的路径代价,一般是地图的宽高先平方再开方
彻底解决对称问题的JPS(Jump Point Search)算法
灰色格子表示:劣点
白色表示:nature point 自然点
红色表示:force point
实际使用时,先从水平和垂直方向搜索关键件,然后搜索四个45°方向。
同时jump point点的选取必须是在直线上。
1.如果在一个方向搜索到了force point 那么这条线上的这个方向停止搜索
2.如果八个方向找到了不止一个关键点,那么就选择f(n)代价值最小的关键点弹出来。
Jps与A*很相似,不同的地方在选择邻点,关键点就是对应邻点。