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所用到的隊列改爲按啓發函數值排列的優先隊列。spa

    假設從狀態S抵達終點的最短距離爲H(S),那麼啓發函數中的h(S)必須知足h(S)<= H(S)。在此基礎上,h和實際的距離越接近,須要計算的節點就越少,效果就越好。若是h(S) = 0,此時A*算法就變成了BFS,效果最差。設計

 

    在解8數字謎題時,若是按照BFS的思路,咱們每次擴展四個節點,分別是空格上移、下移、左移和右移(固然,大多數節點是沒法徹底擴展這四個方向的),一層層搜索以後,若發現了目標狀態,則從目標狀態節點開始向父節點回溯,由此就能夠獲得一個步數最少的解法了。可是BFS是盲目的,所以在搜索過程當中它搜索了不少意義不大的節點。因而咱們開始設計一個加入了必定啓發信息的A*算法(其思路相似於分支限界),代碼以下(參見P223 2.5.4.6小節)blog

 

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);
            }
        }
    }
}
相關文章
相關標籤/搜索