人工智能課,第一個實驗就是八數碼問題。老師讓用3中方式都實現一遍,分別是廣度優先搜索、深度優先搜索和啓發式搜索。心塞╮(╯▽╰)╭。緊急補了一些數據結構的知識,就匆匆上陣。先分享深度優先搜索,後兩篇我會分享廣度優先搜索和啓發式搜索的實現。ios
概念就不講了,百度就好了。簡單說一下個人實現:Situation類存儲節點信息,包括父節點的code值(code是一個字符串,存儲的是八數碼的狀態,好比「138427056」),當前節點的code值,以及深度(深度從0開始,即起始節點深度爲0);在Test.cpp的main函數中,我定義了兩個鏈表open和closed分別存放未被擴展的節點和被擴展的節點。深度優先,新生成的有效的子節點存放在open表的開頭。每次擴展,拿open表的開頭的那個節點來擴展,方法是把open表的頭節點移動到closed表的末端,生成的最多4個有效的子節點存放在open表的開頭。其餘就是比較生成的節點和目標節點是否相等了。數據結構
如下代碼在win8.1下VS2013中測試成功。函數
頭文件Deep.h:oop
#include<iostream> #include"queue" #include"string" #include<list> using namespace std; const string GOAL = "803214765"; class Situation{ private: public: string father; string code;//當前狀態 int deep; Situation up(); Situation down(); Situation left(); Situation right(); bool isGoal(); bool isInOpen(deque<Situation> &open); bool isInClosed(deque<Situation> &closed); void show() const; void show(string) const; void show_deque(deque<Situation> &) const; deque<Situation> showWay(deque<Situation> &closed); void showAnswer(deque<Situation> &closed);//顯示解答 Situation() :father(""), code(""), deep(-1){}; };
Deep.cpp:測試
#include"Deep.h" Situation Situation::up(){ string::size_type loc = code.find('0');//0的位置,從0開始計數 Situation son; son.code = code; son.deep = deep + 1; if (loc>=3){ char temp = son.code[loc];//即0 son.code[loc] = son.code[loc - 3]; son.code[loc-3] = temp; } else{ son.code = ""; } return son; } Situation Situation::down(){ string::size_type loc = code.find('0');//0的位置,從0開始計數 Situation son; son.code = code; son.deep = deep + 1; if (loc<=5){ char temp = son.code[loc];//即0 son.code[loc] = son.code[loc + 3]; son.code[loc + 3] = temp; } else{ son.code = ""; } return son; } Situation Situation::left(){ string::size_type loc = code.find('0');//0的位置,從0開始計數 Situation son; son.code = code; son.deep = deep + 1; if (loc!=0&&loc!=3&&loc!=6){ char temp = son.code[loc];//即0 son.code[loc] = son.code[loc - 1]; son.code[loc - 1] = temp; } else{ son.code = ""; } return son; } Situation Situation::right(){ string::size_type loc = code.find('0');//0的位置,從0開始計數 Situation son; son.code = code; son.deep = deep + 1; if (loc!=2&&loc!=5&&loc!=8){ char temp = son.code[loc];//即0 son.code[loc] = son.code[loc + 1]; son.code[loc + 1] = temp; } else{ son.code = ""; } return son; } bool Situation::isGoal(){ return code == GOAL; } bool Situation::isInOpen(deque<Situation> &open){ /*deque<Situation>::iterator it = open.begin(); while (it != open.end()){ if (code == (*it).code){ return true; } it++; }*/ for (int i = 0; i < open.size();i++){ if (code==open.at(i).code){ return true; } } return false; } bool Situation::isInClosed(deque<Situation> &closed){ /*deque<Situation>::iterator it = closed.begin(); while (it!=closed.end()){ if (code == (*it).code){ return true; } it++; }*/ for (int i = 0; i < closed.size(); i++){ if (code == closed.at(i).code){ return true; } } return false; } void Situation::show() const{ if (!code.empty()){ cout << code[0] << code[1] << code[2] << endl << code[3] << code[4] << code[5] << endl << code[6] << code[7] << code[8] << endl << endl; } else{ cout << "空的" << endl; } } void Situation::show(string code) const{ if (!code.empty()){ cout << code[0] << code[1] << code[2] << endl << code[3] << code[4] << code[5] << endl << code[6] << code[7] << code[8] << endl << endl; } else{ cout << "空的" << endl; } } void Situation::show_deque(deque<Situation> &m_deque) const{ /*deque<Situation>::iterator it = m_deque.begin(); while (it!=m_deque.end()) { (*it).show(); it++; }*/ for (int i = 0; i < m_deque.size();i++){ m_deque.at(i).show(); } } //路徑 deque<Situation> Situation::showWay(deque<Situation> &closed){ //cout << closed.size() << endl; deque<Situation> dequeList; Situation temp = closed.back(); dequeList.push_back(temp); //closed表從後往前,根據father值找到路徑 for (int i = closed.size()-1; i >= 0;i--){ if (temp.father==closed.at(i).code){ dequeList.push_back(closed.at(i)); temp = closed.at(i); } } //cout << dequeList.size() << endl; return dequeList; } void Situation::showAnswer(deque<Situation> &closed){ deque<Situation> way(showWay(closed)); cout << "共須要" << way.size() << "步" << endl; for (int i = way.size() - 1; i >= 0; i--) { way.at(i).show(); } //輸出目標 show(GOAL); }
Test.cpp:人工智能
#include<iostream> #include"Deep.h" using namespace std; void loop(deque<Situation> &open, deque<Situation> &closed, int range); int main(){ string original = "283164705"; Situation first; deque<Situation> open, closed;//open存放未擴展節點,closed存放已擴展節點 int range = 10;//深度界限 first.code = original; first.deep = 0; open.push_back(first); loop(open,closed,range); return 0; } void loop(deque<Situation> &open, deque<Situation> &closed,int range){ Situation a; int i = 0; while (!open.empty()){ cout << i++ << endl; if (open.front().code == GOAL){ cout << "成功:" << endl; a.showAnswer(closed); return; } if (open.empty()){ cout << "失敗" << endl; return; } closed.push_back(open.front()); open.pop_front(); //節點n的深度是否等於深度界限 if (closed.back().deep == range){ //loop(open,closed,range);不能用遞歸 continue; } else{ //擴展節點n,把其後裔節點放入OPEN表的末端 Situation son1 = closed.back().up(); Situation son2 = closed.back().down(); Situation son3 = closed.back().left(); Situation son4 = closed.back().right(); /* 廣度優先搜索和深度優先搜索的惟一區別就是子節點放到open表的位置: (1)廣度優先搜索放到open表的後面 (2)深度優先搜索放到open表的前面 */ if (!son1.code.empty()){ if (!son1.isInOpen(open)&&!son1.isInClosed(closed)){ son1.father = closed.back().code; open.push_front(son1); } } if (!son2.code.empty()){ if (!son2.isInOpen(open) && !son2.isInClosed(closed)){ son2.father = closed.back().code; open.push_front(son2); } } if (!son3.code.empty()){ if (!son3.isInOpen(open) && !son3.isInClosed(closed)){ son3.father = closed.back().code; open.push_front(son3); } } if (!son4.code.empty()){ if (!son4.isInOpen(open) && !son4.isInClosed(closed)){ son4.father = closed.back().code; open.push_front(son4); } } //是否有任何後繼節點爲目標節點 if (son1.isGoal()){ cout << "後繼節點中有目標節點:" << endl; son1.showAnswer(closed); break; } if (son2.isGoal()){ cout << "後繼節點中有目標節點:" << endl; son2.showAnswer(closed); break; } if (son3.isGoal()){ cout << "後繼節點中有目標節點:" << endl; son3.showAnswer(closed); break; } if (son4.isGoal()){ cout << "後繼節點中有目標節點:" << endl; son4.showAnswer(closed); break; } } } }