基于C++和AStar算法求解八数码问题的方案
1 實驗目的
1.1實驗目的
AStar算法是一種在靜態路網中給定目標求解最短路徑的有效搜索方法,它是一種較常見的啟發式搜索算法,常被用于游戲中NPC 與 BOT 的移動計算。
為了加深對ASatr 算法的理解,發揮AStar算法在實際問題中的優勢,在本實驗中選取八數碼問題為背景,將AStar搜索算法應用于尋求八數碼問題的最優路徑,培養運用該算法解決實際問題的能力,體驗AStar算法的優勢與不足,從而對AStar算法擁有更深,更直觀的理解。
2 實驗設計
2.1概述
2.11或圖搜索策略
根據圖的實際背景可分為或圖和與/或圖兩種, AStar算法是或圖搜索算法中的一種常見算法。
圖算法只記錄狀態空間那些被搜索過的狀態,它們組成一個搜索圖叫 G。G由兩張表內的結點組成:
Open 表:用于存放已經生成,且已用啟發式函數作過估計或評價,但尚未產生它們的后繼結點的那些結點,也稱未考察結點。
Closed 表:用于存放已經生成,且已考察過的結點。
結構Tree,它的結點為G 的一個子集。Tree 用來存放當前已生成的搜索樹,該樹由G 的反向邊組成。
或圖的通用搜索策略如下:
設S 0 :初態 S g :目標狀態
產生一個僅由S 0 組成的open 表;
產生一空closed 表;
如果open 為空,失敗退出;
在open 表上按某一原則選出第一個優先結點,稱為 n,將 n 放到closed 表中,并從open 表中去掉 n ;
若n∈ S g ,則成功退出;解為在Tree 中從 n 到S 0 的路徑,或 n 本身。
產生 n 的所有后繼,將后繼中不是 n 的前驅點的點構成集合M,將其裝入G 作為 n 的后繼,
對M 中的元素 P 分別作兩類處理:
(a)若P?G,即 P 不在open 表中也不在closed 表中,則 P 加入open 表, 同時加入搜索圖G 中,對P 進行估計放入Tree 中。
(b)若P∈G,則決定是否更改Tree 中P 到 n 的指針。
8轉 3。
2.1.2AStar算法
在或圖通用搜索算法中,從Open 表中按照某種原則選出第一個優先結點。如果從Open 表中選取結點的策略不同,那么對應的搜索算法也不同。
在A* 算法中,Open 表將根據評估函數()的值選取最佳者,這里的評估函數
𝑓(𝑛)采用以下形式:
𝑓(𝑛) = 𝑔(𝑛) + h(𝑛)
𝑔(𝑛)為從初始結點到當前結點的的路徑代價;
?(n)為當前結點到目標結點的最小代價的估計值。如果該估計值不大于結點 到目標結點的實際代價,則稱該算法為AStar算法。
算法選擇具有最小 f 值的結點進行擴展。
需要指出的是,該算法對 h 函數的選取要求較高。如果?(n)估計過低,那么會擴展過多的結點,造成大量浪費;如果?(n)估計過高,則可能錯過目標,無法找到最優解。?(n)越接近 n 到目標結點的實際代價,算法效率越高。
2.2算法描述
2.2.1狀態的表示
在八數碼問題中,狀態可以被定義為八個數碼的位置信息,每個整數的取值從1 到 8,而數字 0 表示空白方塊,每一個八數碼的盤面代表每一個狀態結點。為了適應AStar算法的需要,每個狀態必須擁有啟發式函數的信息,即𝑓(𝑛),𝑔(𝑛),h(𝑛)的值。為了方便數碼的移動,對于每一個狀態結點,可額外增加空白塊 0 的位置信息(比如zeroRow,zeroCol 表示空白塊所在的行號和列號)。此外,為了輸出路徑的需求,需要記錄最佳路徑中每個結點的父結點,所以對于每個狀態,其數據成員還應該加上一個指向父結點的指針域。
根據以上的分析,可以創建一個狀態結點類,其數據成員如圖 2-1 所示。與狀態密切相關的數組與啟發函數值被聲明為私有成員,零行、零列、父結點等輔助信息被聲明為公有成員。
? 圖 2-1 狀態類的數據成員
2.2.2啟發式函數的選擇
啟發函數𝑓(𝑛) = 𝑔(𝑛) + h(𝑛)。
𝑔(𝑛) 為從初始結點到當前結點的的路徑代價,由于在八數碼問題中,每一步 的路徑權值均為 1,故𝑔(𝑛) 為結點 n 的深度。
?(𝑛)為當前結點到目標結點的最小代價的估計值。在這里,我們采用狀態 n 到目標結點的曼哈頓距離,即所有數字當前位置以最短路徑走到正確位置的步數之和(實現如圖 2-2 所示)。
圖 2-2 計算曼哈頓距離的實現
2.2.3算法流程的偽代碼
創建兩個表,OPEN 表保存所有已生成而未考察的節點(且按照每個結點的 f 值從小到達排序,保證 f 值小的結點位于隊首),CLOSED 表中記錄已訪問過的節點。算起點的估價值,將起點放入OPEN 表。
while(OPEN!=NULL) {從 OPEN 表中取啟發函數值 f 最小的節點 n; if(n 節點==目標節點)成功退出;for(當前節點 n 的每個子節點 X){計算 X 的代價 g; if (X in OPEN){if( X 的代價 g 小于 OPEN 表中結點的代價 g ) {把 n 設置為 X 的父親;更新 OPEN 表中的代價值 g 以及啟發函數值 f;}}if (X in CLOSED) {if( X 的代價 g 小于 CLOSED 表中結點的代價 g ) {把 n 設置為 X 的父親;更新 CLOSED 表中的代價值 g 以及啟發函數值 f;把 X 節點從 CLOSED 中刪去放入 OPEN} }if (X not in both) {把 n 設置為 X 的父親;求 X 的啟發函數值 f; 并將 X 插入 OPEN 表中;}}//end for將 n 節點插入 CLOSED 表中;按照啟發函數值 f 從小到大將 OPEN 表中的節點排序; }//end-while 利用最終的目標結點的指向父親的指針,輸出路徑2.3實驗演示
2.3.1實驗平臺
本實驗采用的編程語言為C++,實驗平臺為Visual Studio 2017。
在模擬八數碼問題的解決過程中,均采用txt 文件輸入輸出。程序從文件中讀取初始狀態與目標狀態,并且將解決路徑輸出到相應文件中。
2.3.2項目結構
項目目錄下,代碼共分為三個文件。State.h 為狀態節點類的定義文件,State.cpp 為類的實現文件,AStar.cpp 為主文件,負責算法的實現。其中 txt 文件負責算法的I/O,算法從 input.txt 文件中讀取輸入,將輸出結果置于output.txt 中。
項目目錄中的內容如圖 2-3 所示,State 類的定義如圖 2-4 所示。
圖 2-3 項目目錄下的文件
圖 2-4 State 類的定義
2.3.3運行結果
八數碼的初始狀態和目標狀態存放在文本文檔input.txt 中,執行程序后,輸出結果路徑被存放到了output.txt 中。
第一次測試的輸入和輸出如圖 2-5 所示;第二次測試的輸入和輸出如圖 2-6 所示。
圖 2-5 第一次測試的輸入與輸出
圖 2-6 第二次測試的輸入與部分輸出(全部輸出路徑見錄屏)
3 總結
3.1實驗中遇到的問題及解決方法
(1)關于Open 表的實現,采用STL 庫中優先隊列這一數據結構。由于優先隊列只能從一端移除數據,所以如果要從 Open 表中刪除或修改指定元素十分困難。這里采取的解決方案是創建一個和Open 優先隊列同步進行操作的OpenTable, OpenTable 基于 vector 實現。
(2)為了方便從Open 表和 Closed 表中找到指定狀態的結點或刪除指定狀態的結點,需要額外設置相關函數(如圖 2-7 所示)。值得注意的是,這里的等號運算符的意義已經被重載,表示兩個狀態數組完全相同。
圖 2-7 deleteFromTable:從表中刪除指定元素;findElementFromTable:從表中尋找指定元素
(3)優先隊列中的結點需要按照 f 值從小到大進行排列,為此需要cmp 仿函數作為優先隊列定義時的第三個參數。cmp 的具體實現如圖 2-8 所示。
? 圖 2-8 cmp 的實現,采取大根堆
3.2結論
AStar 算法一定能保證找到最優解,但效率和啟發函數 h 密切相關。在本實驗中, 選取曼哈頓距離作為啟發式函數 h 相對提高了搜索效率。
試驗結果表明,程序的輸出與預期相符。在該實驗中, AStar算法成功求解了八數碼問題,找到了最優解,并用 C++進行模擬實現,以文件 I/O 的方式展示了結果。綜上所述,實驗達到預期目的,加深了對AStar算法的理解,熟悉了算法背后的整個流程,并成功解決了實際問題,培養了動手實踐能力。
一定能保證找到最優解,但效率和啟發函數 h 密切相關。在本實驗中, 選取曼哈頓距離作為啟發式函數 h 相對提高了搜索效率。
試驗結果表明,程序的輸出與預期相符。在該實驗中, AStar算法成功求解了八數碼問題,找到了最優解,并用 C++進行模擬實現,以文件 I/O 的方式展示了結果。綜上所述,實驗達到預期目的,加深了對AStar算法的理解,熟悉了算法背后的整個流程,并成功解決了實際問題,培養了動手實踐能力。
總結
以上是生活随笔為你收集整理的基于C++和AStar算法求解八数码问题的方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: autojs自动阅读脚本源代码免费分享
- 下一篇: 大数据学习入门难,给初学者支招