A*算法

推荐链接:详细A*,详细A*的翻译,A*算法入门,A*算法

A*算法与普通算法相比多了一个h()估价函数,用来估计此点到终点的代价,h()函数有多种计算方式,常用的是曼哈顿距离(也即是水平距离差+竖直距离差)

g()指的是从起点到该点的距离,计算也很简单,直接父节点g()加1 就好了

f()=g()+h()算出来充当该点权值,f()越大越应该优先扩展

h()算法好坏能很大程度上决定A*算法的效率,但对于那种无障碍的路直接拿h()当权值效率更高,因为离终点更近,如八数码

h()也不是能随便定义的,很容易就导致WR,定义的原则如下:

h()一定要相容,则A算法转变为A*算法。


算法流程:

1,把起始格添加到开启列表。

2,重复如下的工作:

a) 寻找开启列表中F值最低的格子。我们称它为当前格。

b) 把它切换到关闭列表。

c) 对相邻的格中的每一个格子

* 如果它不可通过或者已经在关闭列表中,略过它。反之如下。

* 如果它不在开启列表中,把它添加进去。把当前格作为这一格的父节点。记录这一格的F,G,和H值。

* 如果它已经在开启列表中,用G值为参考检查新的路径是否更好。更低的G值意味着更好的路径。如果是这样,就把这一格的父节点改成当前格,并且重新计算这一格的G和F值。如果你保持你的开启列表按F值排序,改变之后你可能需要重新对开启列表排序。

#如果它已经在关闭列表中,可能该点G值比旧点的更低,如果是这样,就把这一格的父节点改成当前格,并且重新计算这一格的G和F值。删除关闭列表的旧点,添加新点到开始列表中,如果你保持你的开启列表按F值排序,改变之后你可能需要重新对开启列表排序。(此步骤有时不需要,原因在下面)


d) 停止,当你

* 把目标格添加进了关闭列表(注解),这时候路径被找到,或者

* 没有找到目标格,开启列表已经空了。这时候,路径不存在。

3.保存路径。从目标格开始,沿着每一格的父节点移动直到回到起始格。这就是你的路径。


有时要检查关闭列表的原因:

如果图是一个不规则的图,比如一个游戏里,有几个传送门,这样同一个点如果经过传送门的话,路径会大大缩短,这样就需要检查开始和关闭列表来更新f值,如果是一个不包含捷径(传送门)的图,那样就可以用个数组来标记已访问过的节点,这样就可以不用关闭列表,也不用检查开始列表来更新f值。


需要检查关闭列表时候:

数据结构:

multiset中元素的迭代器不因增删其他元素而失效
struct Node {
	int status;
	int f; int g; int h;
	int parent; // 父状态
	char move; //经由何种动作到达本状态
};
multiset open; //按f从小到大排序
multiset closed; //按f从小到大排序

map::iterator> inOpen;
//元素的 first代表状态,second代表first在open表中的地址
map::iterator> inClosed;
//元素的 first代表状态,second代表first在closed表中的地址

伪代码如下:

open=[Start]
closed=[]
while open不为空 {
 	从open中取出估价值f最小的结点n
	if n == Target then
	return 从Start到n的路径 // 找到了!!!
 	else {
 		for n的每个子结点x {
			if x in open {
				计算新的f(x)
				比较open表中的旧f(x)和新f(x)
				if 新f(x) < 旧f(x) {
					删掉open表里的旧x,加入新x
	 			} //新旧x的父亲,以及f值不同
 			}
 			else if x in closed {  //有些图可以直接省去 
				计算新的f(x)
				比较closed表中的旧f(x)和新f(x)
 				if 新f(x) < 旧f(x) {
					remove x from closed
					add x to open
 				}// 比较新f(x)和旧f(x) 实际上比的就是新旧g(x),因h(x)相等
 			}
				
			else {
				// x不在open,也不在close,是遇到的新结点
				计算f(x) add x to open
			}
		} // for n的每个子结点x
		add n to closed
	}
}
//open表为空表示搜索结束 



不需要查关闭列表:

数据结构:

priority_queue open;
bool closed[maxn];

伪代码如下:

open=[Start]
closed=[]
while open不为空 
{
	从open中取出估价值f最小的结点n
	
	if n == Target then
	return 从Start到n的路径 // 找到了!!!
	for n的每个子结点x {
		if x in closed  跳过;
		else 计算f(x) add x to open	
	}
	add n to closed
} 



你可能感兴趣的:(搜索:A*算法,搜索)