A*算法
A*算法
算法目的
找到从起点到终点间的最短(最优)路径。
流程
初始化搜索区域
把搜索区域简化为二维数组,数组每一个元素的状态都只有可走和不可走。每一个元素被称为节点,也就是实际图中每一个块的中心点。
搜索
① 从起点A开始,把起点节点加入open list(关注集)。open list是待检查的列表,后期只会从这个列表中找节点作为起始向外扩张。
② 检查所有与A相邻的方格,把其中所有可走的格都加入open list,并把A设为这些方格的父节点。
③ 把A从open list移除,加入close list。close list中的格子都不再需要关注。
如图,与A相邻的格子都加入了open list,并记录自己的父节点A(图中用可视化指针表示),同时A已经被移出open list,后续不用再关注。
④ 之后需要从open list中找一个格子作为起点。重复之前的步骤。但是区别于dijkstra算法,并不需要遍历全部的open list,而是有目的、有优先级地去访问。那么这个优先级根据什么来定呢,是根据
路径排序
值的计算
其中
如果是上下左右相邻的格子(曼哈顿距离为 1),那么移动成本为 10。如果是对角线相邻的格子(曼哈顿距离为
如图中①、②格子所示,
继续搜索
⑤ 从上述步骤中找出
⑥ 检查所有与它相邻的方格,忽略其中在 close list 中或是不可走的方格,如果方格不在open list 中,则把它们加入到 open list 中。
注意
一个节点一旦被加入了open list,那它的
由于此时它周围的所有格子都已经在open list中,所以不做改变,也无需更新
$G$值更新
下一步,找
检查它周围的格子发现有两个不在open list,于是把它们加入。左边的格子到它父节点的距离是14,它的父节点
i
墙正下方的格子在这里被认为是不可达的。因为这么走和墙角的距离为0,会碰到墙角。
但是在其他的情况下又有可能可达,比如一些奇形怪状的节点可以确保穿越墙角时不碰到。
之后按这个方法不断搜索,直到找出最短路:
这里蓝色格子是close list。现在只是搜到了终点。为了得到路径,只需从终点开始按父节点指针回溯到起点:
例子
可见,如果一个节点在新的父节点的open list中可以拥有更小的
启发函数
概念
上边说根据公式
确定优先级,但是可以把每个变量都扩展成函数:
对算法的影响
各种情况
① 当启发函数
也就是在搜索过程中不考虑与目标的距离,而是以起点为中心公平地向四周搜索,此时退化为了Dijkstra算法。Dijkstra 算法总是找到最短路径,但它没有启发性估计,所以通常会遍历更多节点,效率较低。
② 当
然而,在实际情况中,往往难以精确估计到目标节点的实际代价,尤其在没有到达目标节点之前,这种理想情况较难实现。
③ 当
为什么这种情况能保证最优解?
既然
④ 当
为什么这种情况能不保证最优解?
相反,当
⑤ 当
图解
情况①,当启发函数
算法只关心当前格子和起点的距离,搜索时会经常出现两个格子距离一样的情况,而算法又必须优先搜索最小的,所以就要经常左右横跳去搜,很慢。
情况②,当启发函数等于实际代价:
这种情况下会多走一些弯路,但是最终也能找到最短路。
情况③,当启发函数占主导:
这时候如果只按启发函数值来搜,就可能发生图中的情况,它可能搜索的格子更少,但是会被启发函数误导,找到的并不是最短路。
伪代码
伪代码
A* Algorithm |
---|
起点放入open list while true if open list为空: 搜索失败,结束 取open list中 if 节点为终点: 返回路径,结束 遍历当前不在close list中的节点 if 节点在open list里: 更新 else 计算当前节点 |
python实现
Question
不知道是否需要。
复杂度
A*算法的时间和空间复杂度都为:
其中
因为每搜一步,就要遍历当前所有open list的节点,越往后这个数字会指数级增加。
如果启发函数
如果
可视化
BUG!!!
我正在研究怎么把html模板嵌入进来,这部分功能暂不提供。
A*算法的性质
定理一
当问题有解时,A*算法一定能找到最佳路径。对有限图,如果从初始节点
引理一
对无限图,若有从初始节点s到目标节点t的路径,则A*不结束时,在OPEN表中即使最小的一个f值也将增到任意大,或有
算法不结束,也就是会搜到更多的点,图中的节点可能是无限的,那么
引理二
A*结束前,OPEN表中必存在
对于一个在最优路径上的节点
若
疑点
定理二
对无限图,若从初始节点s到目标节点t有路径存在,则A*一定成功结束。
利用引理一、二证矛盾:
根据引理一,若A*不结束,则open中所有的点都有:
根据引理二,A*结束前必存在节点n使得
推论一
open表上任何具有
i
证明暂略。
定理三,可采纳性定理
若存在从初始节点s到目标节点t有路径,则A*必能找到最佳解结束。
推论二
对于被A*选作扩展的任一节点n,有
定理四
设对同一个问题定义了两个A*算法
在具有一条从s到t的路径的隐含图上,搜索结束时,由
启发信息更少,就说明算法倾向于求稳,它会在扩展一些节点的基础上额外扩展一些来保证最优解。
如果
A*算法改进
存在问题
对于已在open中的点,如果发现它在有新父亲的情况下需要更新父亲节点并重新放入open,这会导致某些节点被反复修改指针和
原因是在前面的扩展中,并没有找到从初始节点到当前节点的最短路径。
解决
改进的条件
可采纳性不变;不多扩展节点;不增加算法的复杂性。
限制h
对h增加适当的限制,使得第一次扩展一个节点时,就找到了从s到该节点的最短路径。
对一个启发函数h,如果对所有节点
则称h单调。
定理五
若
即:当A*选
定理六
若
疑问
这个单调性是什么意思?直观体现?单调性有关的定理是为什么?
改进算法
根据推论一和推论二:
OPEN表上任一具有
这样可以把open表中的所有点分为两类:
设
修正后的评估过程 |
---|
open= loop if open is empty then exit with fail; nest = if nest is not empty then n = nest中 else n = first(open), |
其实就是在从open中拿节点时优先拿