人工智能课,第一个实验就是八数码问题。老师让用3中方式都实现一遍,分别是广度优先搜索、深度优先搜索和启发式搜索。心塞╮(╯▽╰)╭。紧急补了一些数据结构的知识,就匆匆上阵。先分享深度优先搜索,后两篇我会分享广度优先搜索和启发式搜索的实现。
概念就不讲了,百度就行了。简单说一下我的实现:Situation类存储节点信息,包括父节点的code值(code是一个字符串,存储的是八数码的状态,比如“138427056”),当前节点的code值,以及深度(深度从0开始,即起始节点深度为0);在Test.cpp的main函数中,我定义了两个链表open和closed分别存放未被扩展的节点和被扩展的节点。深度优先,新生成的有效的子节点存放在open表的开头。每次扩展,拿open表的开头的那个节点来扩展,方法是把open表的头节点移动到closed表的末端,生成的最多4个有效的子节点存放在open表的开头。其他就是比较生成的节点和目标节点是否相等了。
以下代码在win8.1下VS2013中测试成功。
头文件Deep.h:
#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;
}
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。