很久没写博客了,今天就来讲讲A*算法吧。
前言:
比赛中,搜索是一种简单有效的拿分方法。但搜索也分很多种,如何搜索效率更高,可以拿到更多分,是一个很有意义的问题。
A*作为一种高效的、应用广的搜索算法,是我们所必须掌握的。
定义:
让我们先看看A*算法的定义:
A*(A-Star)算法是静态路网中求解最短路径的最有效的搜索算法之一,也是解决许多搜索问题的有效算法。
算法中的距离估算值与实际值越接近,最终搜索速度越快。
经典例题:
对于上面的定义,一些没有接触过A*的人可能会有些懵逼。没关系,我们先不管上面的定义,先来看一道例题:
如图一,绿色为A点,红色为B点,蓝色为围墙,一个方格为一个点。
我们要求A点到B点的最短路径,一个点可以走到它八个方向上与它相连的点,但不能穿过围墙。
(图一)
A*算法操作模拟:
接下来,我们将用A*算法模拟上面这道例题,看完后,你基本就可以理解A*算法了。
从起点A开始走,先把A点加入open list(开放列表)中,open list中的点表示你接下来可能会经过这些点(也可能不会经过),现在open list中只有一个点,它就是起点A。
查看与起点A相连的点(围墙除外),把其中可到达的点加入open list中,并把起点A设为这些点的父亲。
把起点A从open list中移除,加入到close list(封闭列表)中,close list中的每个点都是不需要再关注的。
下一步,我们需要从open list中选一个点,按上面描述的一样重复前面的操作。
但要选哪个点呢?选具有最小F值的那个点。
那么,F表示什么呢?请看下面。
估价函数:
对于每个状态,都有一个对应的F值。
F表示从初始状态经由当前状态到目标状态的代价估计,我们称之为估价函数。
很显然,F=G+H;
其中G表示初始状态到当前状态的实际代价。
H表示当前状态移动到目标状态的估计成本。
上面的内容听起来有点公式化,我们还是拿之前那道例题来说明吧。
在例题中,F表示从起点A经由当前点再到终点B的代价估计。
G表示从起点A到当前点的实际代价。
H表示当前点到终点B的估计成本。
有人可能会问,为什么H不能也像G那样表示实际代价呢?
很简单,我们又没有走过一条从当前点到终点B的实际路径,怎么可能知道实际代价呢?
我们来讲讲G和H怎么求。
G可以由当前点的父亲的G值递推而来。
H的话呢,你先预处理出每个点到终点B的估计距离,H就是当前点的该值。
如何求一个状态到终点状态的估计距离,要视情况而定。
在这里,我们可以假设每个点到终点B的估计距离是该点到终点B的忽略围墙的最短路。
但是,有一点要注意的是,H的大小很大程度上影响了答案与运行时间,选择估计方式要慎重。
比如H不能大于实际距离,否则答案十有八九会错。
H也不能太小,否则运行时间就和普通搜索没啥区别了。
同时,我们还要考虑计算H的时间复杂度。
像我刚才令H等于该点到终点B的忽略围墙的最短路,但很多时候,时限是不够我们求每个点到终点的最短路的。
这时,我们就可以考虑求欧几里得距离之类的。
A*算法操作模拟:
接下来,让我们继续回到上面例题的A*算法操作模拟。
上面,我们选中了一个具有最小F值的点,把它加入到close list里面,把与它相连的的点(围墙与已经在close list中的点除外)加入到open list中,并把它设为它们的父亲。
如果有与它相连的点已经在open list里面了,则判断这条路径是否更优,也就是说经由我们选中的点的G值是否
比原本的G值更小,是则把那个点的父亲设为我们选中的点,并更新那个点的G和F。否则不做任何操作。
接下来,我们将不断重复这个过程,直到我们把终点也加入了open list中,答案就为终点的G值。
归纳:
下面,我们来归纳一下A*算法的步骤。
1° 把起点加入open list
2° 从open list中选一个F值最小的,把其移出open list,加入close list
3° 把与选中的点相连的能到达的且不在close list的点加入open list,若其已在open list中则判断G值能否更新。
4° 重复2°到3°的过程,直到终点被加入到open list中,则输出终点的G值。
总结
A*的本质是一种基于贪心的搜索算法,适用于一些求最短距离、最少步数的题。
因为它每一步都选的是估计能最快到达终点的点来走,这样就通过局部最优保证整体最优,能达成两个性质:
1、最先找到的终点一定最优。
2、每一步选的点的G值一定是起点到该点的最优路线的值。
可能讲得不是很清楚,不过大家自己画一下图应该可以明白的。
最后,感谢大家的支持。
欢迎各路大佬指正本文的问题。
如果你认为本文写得好,欢迎点赞与转发(转发请标明出处与原文链接)。