使用AStar算法解决八数码问题
八數(shù)碼問(wèn)題是一個(gè)經(jīng)典的搜索問(wèn)題,本文將介紹如何使用啟發(fā)式搜索—— AStar 算法來(lái)求解八數(shù)碼問(wèn)題。
問(wèn)題描述
八數(shù)碼問(wèn)題的A星搜索算法實(shí)現(xiàn)
要求:設(shè)計(jì)估價(jià)函數(shù),并采用c或python編程實(shí)現(xiàn),以八數(shù)碼為例演示A星算法的搜索過(guò)程,爭(zhēng)取做到直觀、清晰地演示算法,代碼要適當(dāng)加注釋。
八數(shù)碼難題:在3×3方格棋盤(pán)上,分別放置了標(biāo)有數(shù)字1,2,3,4,5,6,7,8的八張牌,初始狀態(tài)S0可自己隨機(jī)設(shè)定,使用的操作有:空格上移,空格左移,空格右移,空格下移。試采用A*算法編一程序?qū)崿F(xiàn)這一搜索過(guò)程。
算法描述
預(yù)估值的設(shè)計(jì)
A* 算法的花費(fèi)為 f(n) = g(n) + h(n),其中 g(n) 為搜索深度,定義為狀態(tài)單元 state 的成員變量,在每次生成子節(jié)點(diǎn)時(shí)將其加一。h(n) 為不對(duì)位的將牌數(shù),將該部分的計(jì)算重載于 state 的小于運(yùn)算符中,并將 f(n) = g(n) + h(n) 的值作為狀態(tài)單元的比較值。
數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)
- 每個(gè)狀態(tài)用一個(gè)結(jié)構(gòu)體表示,其中 depth 為狀態(tài)深度,str 為該狀態(tài)字符串,并重載小于運(yùn)算符用于計(jì)算最優(yōu)。
- open 表使用優(yōu)先隊(duì)列 priority_queue,實(shí)現(xiàn)在 O(logn) 的時(shí)間復(fù)雜度內(nèi)獲取最優(yōu)值。
- close 表使用哈希集合 unordered_set,實(shí)現(xiàn)在 O(1) 時(shí)間復(fù)雜度內(nèi)判斷某狀態(tài)是否已位于 close 表中。
- 而為了得到最優(yōu)搜索路徑,還需要將每個(gè)狀態(tài)的前驅(qū)加以保存,前驅(qū)表 pre 我使用了哈希表 unordered_map,模板類型為 pair<string, string>,表示 key 的前驅(qū)為 value。
代碼
#include<iostream> #include<string> #include<vector> #include<queue> #include<unordered_map> #include<unordered_set> #include<stack> using namespace std;class Solution { private:static string targetStr;const vector<vector<int>> dirs = { {-1,0},{1,0},{0,-1},{0,1} }; // 四個(gè)移動(dòng)方向struct state{string str;int depth;state(string s, int d) : str(s), depth(d) {}bool operator < (const state& s) const {int cnt1 = 0, cnt2 = 0;for (int i = 0; i < 9; ++i) {if (s.str[i] != targetStr[i])++cnt1;if (this->str[i] != targetStr[i])++cnt2;}return cnt1 + this->depth < cnt2 + s.depth; // f(n) = g(n) + h(n) }};inline void swapChr(string& child, int iniInd, int childInd) { // 交換字符,完成移動(dòng)child[iniInd] = child[childInd];child[childInd] = '0';}void printPath(unordered_map<string, string>& pre, string path) { // 輸出路徑stack<string> st;while (path != "None") {st.emplace(path);path = pre[path];}int cnt = 0;while (++cnt && !st.empty()) {string str = st.top();st.pop();cout << "step" << cnt << ": " << str.substr(0, 3) << endl<< " " << str.substr(3, 3) << endl << " " <<str.substr(6, 3) << endl << string(15, '-') << endl;}} public:void eightDigitalQues(const string& ini, const string& target) {targetStr = target;priority_queue<state> open;unordered_set<string> close;unordered_map<string, string> pre;open.emplace(ini, 0);pre[ini] = "None";while (!open.empty()) {string n = open.top().str;int d = open.top().depth;open.pop();close.emplace(n);if (n == target) {break;}int iniInd = n.find('0');int x = iniInd / 3, y = iniInd % 3;for (const auto& dir : dirs) { // 嘗試選擇四個(gè)方向int nx = x + dir[0], ny = y + dir[1];if (nx >= 0 && nx <= 2 && ny >= 0 && ny <= 2) { // 滿足移動(dòng)后下標(biāo)滿足條件int childInd = nx * 3 + ny;state childState(n, d + 1);swapChr(childState.str, iniInd, childInd);if (close.count(childState.str)) // 如該狀態(tài)已加入close表,則跳過(guò)continue;open.emplace(childState); // 加入滿足條件的子狀態(tài)pre[childState.str] = n; // 更新前驅(qū)}}}printPath(pre, target); // 輸出流程return;} }; string Solution::targetStr; int main() {Solution S;string ini, target;cin >> ini >> target;S.eightDigitalQues(ini, target);cin.get(); }運(yùn)行結(jié)果
輸入
原狀態(tài):283164705, 目標(biāo)狀態(tài):123804765
輸出
總結(jié)
以上是生活随笔為你收集整理的使用AStar算法解决八数码问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [现代控制理论]8_LQR控制器_sim
- 下一篇: c语言除法连续运算,单片机C语言快速精度