A*算法与8数字谜题(参见《算法》P226习题2.5.32)

    A*算法的目的是找到一条从起始状态到最终状态的最短路径。

    在A*算法中,需要在每个点计算启发函数:f(S) = g(S) + h(S),其中g(S)是从起点到S点的距离,h(S)是对从S点到终点的最短距离的估计值。

    如果把g(S)当作深度,又令h(S) = 0,则A*算法就变成了BFS

    A*算法对BFS的改进在于把BFS所用到的队列改成按启发函数值排列的优先队列。

    假设从状态S抵达终点的最短距离为H(S),那么启发函数中的h(S)必须满足h(S)<= H(S)。在此基础上,h和实际的距离越接近,需要计算的节点就越少,效果就越好。如果h(S) = 0,此时A*算法就变成了BFS,效果最差。

 

    在解8数字谜题时,如果按照BFS的思路,我们每次扩展四个节点,分别是空格上移、下移、左移和右移(当然,大多数节点是无法完全扩展这四个方向的),一层层搜索之后,若发现了目标状态,则从目标状态节点开始向父节点回溯,由此就可以得到一个步数最少的解法了。但是BFS是盲目的,因此在搜索过程中它搜索了很多意义不大的节点。于是我们开始设计一个加入了一定启发信息的A*算法(其思路类似于分支限界),代码如下(参见P223 2.5.4.6小节)

 

A*()
{
	// open表,用优先队列实现,用来保存待扩展的节点(改进自BFS中的队列)。
	PriorityQueue open;
    
	// closed表,用HASH表或者其他能够高效检索的数据结构实现,用来保存已经扩展过的节点(可以考察一个状态是否已经被产生过)。
	SymbolTable closed;

	open.Add(起始节点);
     
    while(!PriorityQueueEmpty(open))
    {
		// 从open表中弹出一个最优的待扩展节点
        S = PriorityQueueDeleteMax(open)); 

        closed.Insert(S);
         
        // 如果S就是目标状态则结束
        if(S == GOAL)
        {
            return OVER;
        }
         
        // 尝试扩展S的所有子节点
        while(childS = S.nextChild())
        {
            // 如果当前节点尚未被产生过
            if(!closed.isInclude(childS))
            {
                // 则将这个节点添加到open表中
                PriorityQueueInsert(open,childS);
            }
        }
    }
}

 

  

 

 

 

 

posted @ 2013-12-15 11:32  姚来飞  阅读(666)  评论(0编辑  收藏  举报