A*算法学习笔记

1.   状态空间图

           状态空间图 (状态图)实际上是一类问题的抽象表示。如:许多智力问题(八数码问题、梵塔问题、旅行商问题、八皇后问题、农夫过河问题等)。实际问题(如路径规划、定理证明、演绎推理、机器人行动规划等)都可以归结为在某一状态图中寻找目标或路径的问题。

       例如:农夫过河问题:有一个农夫带一条狼、一只羊和一棵白菜过河。如果没有农夫看管,则狼要吃羊,羊要吃白菜。但是船很小,只够农夫带一样东西过河。问农夫该如何解此难题?

农夫过河问题状态空间法表示

n       以向量(人,狼,羊,菜)表示状态,其中每个变元可取0或1,取0表示在左岸(出发点),取1表示在右岸

n       初态是:(0,0,0,0)

n       终态是:(1,1,1,1)

n       非法中间状态有:

(0,0,1,1),(0,1,1,0),(0,1,1,1),
(1,1,0,0),(1,0,0,1),(1,0,0,0)。

 

2.状态空间法

问题的状态空间表示(状态图表示)

状态空间的三元组(S, O, G)表示. S:初始状态集合; O: 操作集合; G:目标状态集合

状态空间的搜索策略(状态图搜索):广度优先搜索, 深度优先搜索, 启发式搜索

        状态空间搜索,就是将问题求解过程表现为从初始状态到目标状态寻找这个路径的过程。由于求解问题的过程中分枝有很多,主要是求解过程中求解条件的不确定性,不完备性造成的,使得求解的路径很多这就构成了一个状态空间。问题的求解实际上就是在状态空间中找到一条路径可以从开始到结果。这个寻找的过程就是状态空间搜索。

       广度优先是从初始状态一层一层向下找,直到找到目标 为止。

       深度优先是按照一定的顺序先查找完一个分支,再查找另一个分支,以至找到目标为止。

       广度和深度优先搜索有一个很大的缺陷就是他们都是在一个给定的状态空间中穷举。这在状 态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不预测的情况下就不可取了。他的效率 实在太低,甚至不可完成。在这里就要用到启发式搜索了。

3.启发式搜索

       启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价是十分重要的。采用不同的估价可以有不同的效果。我们先看看估价是如何表示的。 
      
启发中的估价是用估价函数表示的,如:  f(n) = g(n) + h(n) 
      
其中f(n)是节点n的估价函数,g(n)实在状态空间中从初始节点到n节点的实际代价h(n)是从n到目标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。g(n)代表了搜索的广度的优先趋势。但是当h(n) >> g(n)时,可以省略g(n),而提高效率。

        启发式搜索其实有很多的算法,比如:局部择优搜索法、最好优先搜索法等等。当然A*也是。这些算法都使用了启发函数,但在具体的选取最佳搜索节点时的策略不同。像局部择优搜索法,就是在搜索的过程中选取“最佳节点”后舍弃其它的兄弟节点,父亲节点,而一直得搜索下去。这种搜索的结果很明显,由于舍弃了其他的节点,可能也把最好的节点都舍弃了,因为求解的最佳节点只是在该阶段的最佳并不一定是全局的最佳。最好优先就聪明多了,它在搜索时,便没有舍弃节点(除非该节点是死节点),在每一步的估价中 都把当前的节点和以前的节点的估价值比较得到一个“最佳的节点”。这样可以有效的防止“最佳节点”的 丢失。其实A*算法也是一种最好优先的算法。只不过要加上一些约束条件罢了。由于在一些问题求解时,我们希望能够求解出状态空间搜索的最短路径,也就是用最快的方法求解问题,A*就是干这种事情的!我们先下个定义,如果一个估价函数可以找出最短的路径,我们称之为可采纳性。

4. A*算法

         A*算法是一个可采纳的最好优先算法。A*算法的估价函数克表示为: f’(n) = g’(n) + h’(n) 
       
这里,f’(n)是估价函数,g’(n)是起点到n节点的最短路径值h’(n)n到目标的最短路经的启发值。由 于这个f’(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g’(n),但 g(n)>=g’(n) 才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h’(n),但h(n)<=h’(n)才可(这一点特别的重要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。

        其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数,h(n)=0,这种h(n)肯定小于h’(n),所以由前述可知广度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。 
        
再说一个问题,就是有关h(n)启发函数的信息性。h(n)的信息性通俗点说其实就是在估计一个节点的值时的约束条件,如果信息越多或约束条件越多则排除的节点就越多,估价函数越好或说这个算法越好。这就是为什么广度优先算法的那么臭的原因了,谁叫它的h(n)=0,一点启发信息都没有。

 A*算法的特征:

A*是可采纳的:只要最短路径存在,就一定能找出.

如果有 h1(n) <= h2(n) <= h*(n), 那么h2h1展开更少的节点.

广度优先搜索是当h(n)=0时的A*算法的特例.

对一个好的h(n)的评价是:h(n)h*(n)的下界之下,并且尽量接近h*(n).

        搜索过程中设置两个表OPENCLOSEDOPEN表保存了所有已生成而未考察的节点,CLOSED 表中记录已访问过的节点。算法中有一步是根据估价函数重排OPEN表。这样循环中的每一 步只考虑OPEN表中状态最好的节点。

算法的伪程序如下 
Best_First_Search()
{
   
Open = [起始节点]; Closed = [];
   
while ( Open表非空 )
   
{
         Open中取得一个节点X,并从OPEN表中删除。
        
if (X是目标节点)
        
{
              求得路径PATH;返回路径PATH
        
}
         for (每一个X的子节点Y)
        
{
             if( Y不在OPEN表和CLOSE表中 )
            
{
                  Y的估价值;并将Y插入OPEN表中;//还没有排序
            
}
             else  if( YOPEN表中 )
            
{
                  if( Y的估价值小于OPEN表的估价值 )
                
     更新OPEN表中的估价值;
            
}
             else //YCLOSE表中
            
{
                 if( Y的估价值小于CLOSE表的估价值 )
                
{
                     更新CLOSE表中的估价值;
                    
CLOSE表中移出节点,并放入OPEN表中;
                
}
             }
             X节点插入CLOSE表中;
            
按照估价值将OPEN表中的节点排序;
        
}//end for
     }//end while
}//end func

参考资料:

1.A*算法理论与实践

http://www.java3z.com/cwbwebhome/article/article2/2825.html

2.http://www.cnblogs.com/kanego/archive/2011/08/30/2159070.html

 

展开阅读全文

没有更多推荐了,返回首页