实验二 八数码问题
一、实验目的
本实验课程是计算机、智能、物联网等专业学生的一门专业课程,通过实验,帮助学生更好地掌握人工智能相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对智能程序、智能算法等有比较深入的认识。
1.掌握人工智能中涉及的相关概念、算法。
2.熟悉人工智能中的知识表示方法;
3.熟悉盲目搜索和启发式搜索算法的应用;
4.掌握问题表示、求解及编程实现。
5.掌握不同搜索策略的设计思想、步骤、性能。
二、基本要求
1.实验前,复习《人工智能》课程中的有关内容。
2.准备好实验数据。
3.编程要独立完成,程序应加适当的注释。
4.完成实验报告。
三、实验软件
使用C或C++(Visual studio)(不限制语言使用)。
四、实验内容:
1.在图1,33的方格棋盘上,摆放着1到8这八个数码,有1个方格是空。
图1
2.如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态(图1左)到目标状态(图1右)。
3.可自行设计初始状态。目标状态为数字从小到大按顺时针排列。
4.分别用广度优先搜索策略、深度优先搜索策略和启发式搜索算法(A算法)求解八数码问题;分析估价函数对启发式搜索算法的影响;探究各个搜索算法的特点。
五、学生实验报告要求
1、实验报告需要包含以下几个部分
(1)状态表示的数据结构
struct states
{
int STATE[3][3]={ {1,2,3},{8,0,4},{7,6,5} };;//节点所表示状态的基本信息
states* PARENT_NODE = NULL;//指针域指向当前节点的父节点
string ACTION;//从父节点表示的状态转换为当前状态所使用的操作
int DEPTH;//当前节点在搜索树中的深度
double PATH_COST = 0;//从起始节点到当前节点的路径代价
bool operator ==(const states& p)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (STATE[i][j] != p.STATE[i][j])
return false;
}
}
return true;
}
};
流程图:
注意:1、这里dfs加入open表为list的前面,区别与bfs,bfs为list表后,其他的大同小异
2、在判断是否重复那里,dfs是通过父节点寻求路径比对,BFS是比对open和close两边不重复
DFS:深度优先搜索
(1)搜索产生的状态空间图
程序清单
注释掉的为open和close的输出,想要的可以加上
#include<string>
#include<list>
#include <iostream>
using namespace std;
struct states
{
int STATE[3][3]={ {1,2,3},{8,0,4},{7,6,5} };;//节点所表示状态的基本信息
states* PARENT_NODE = NULL;//指针域指向当前节点的父节点
string ACTION;//从父节点表示的状态转换为当前状态所使用的操作
int DEPTH;//当前节点在搜索树中的深度
double PATH_COST = 0;//从起始节点到当前节点的路径代价
bool operator ==(const states& p)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (STATE[i][j] != p.STATE[i][j])
return false;
}
}
return true;
}
};
ostream &operator <<(ostream&out, const states &node)
{
out << "----------------------" << endl;
out << "Action" << node.ACTION << endl;
out << "深度为" << node.DEPTH << endl;
out << "cost:" << node.PATH_COST << endl;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
out << node.STATE[i][j] << " ";
}
out << endl;
}
return out;
}
list<states*> open;//opem表
list<states*> close;//close表
int limit;//限制
states state_end;
//在父指针下判断其路劲是否有重复的
bool if_repeat(states* data)
{
states* pre = data;
while (pre->PARENT_NODE != NULL)
{
pre = pre->PARENT_NODE;
if (*data == *pre) return true;
}
return false;
}
states* creat_states(states* node, int i, int j, int dx, int dy)
{
states* data = new states();
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
data->STATE[i][j] = node->STATE[i][j];
}
}
data->STATE[i][j] = data->STATE[i +dx][j + dy];
data->STATE[i + dx][j + dy] = 0;
data->PARENT_NODE = node;
data->DEPTH = node->DEPTH+1;
if (dx == -1) data->ACTION = "向上移动";
else if (dx == 1) data->ACTION = "向下移动";
else
{
if (dy == -1) data->ACTION = "向左移动";
else if (dy == 1) data->ACTION = "向右移动";
}
return data;
}
//int dept = 0;//计算走了多少步
//展示路径
void showpath(states* node)
{
if (node->PARENT_NODE != NULL)
{
showpath(node->PARENT_NODE);
//dept++;
}
cout << "----------------------" << endl;
cout << node->ACTION << endl;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cout << node->STATE[i][j] << " ";
}
cout << endl;
}
}
//销毁
void destroy_close()
{
states * data;
while (!close.empty())
{
data = close.front();
close.pop_front();
delete data;
}
while (!open.empty())
{
data = open.front();
open.pop_front();
delete data;
}
}
/*void show_open()
{
if (!open.empty())
{
cout << "-----------showopen---------------" << endl;
list<states*>::iterator it;
for (it = open.begin(); it != open.end(); ++it)
{
cout << **it << endl;
}
cout << "-----------openend---------------" << endl<<endl;
}
else
{
cout << "-------------open表为空----------" << endl<<endl;
}
}
void show_close()
{
if (!close.empty())
{
cout << "-----------showclose-------------" << endl;
list<states*>::iterator it;
for (it = close.begin(); it != close.end(); ++it)
{
cout << **it << endl;
}
cout << "-----------closeend---------------" << endl<<endl;
}
else cout << "------------close表为空------------" << endl<<endl;
}
int i = 0;*/
void nextStep()
{
/*cout << "-------------------------------------------" << i << "-----------------------------------------------" << endl;
i++;
show_open();
show_close();*/
if (open.empty()) return;//open表为空
//否则将元素从open表中取出
states*node = open.front();
open.pop_front();
close.push_front(node);
if (node->DEPTH >= limit - 1)
{
nextStep();
return;
}
//找到那个0节点
int i;
int j;
for (i = 0; i < 3; i++)
{
for ( j= 0; j < 3; j++)
{
if (node->STATE[i][j] == 0)
break;
}
if (j != 3) break;
}
//扩展node后面的所有节点
states*d;
//向四个方向扩展
//下
if (i + 1 >= 0 && i + 1 < 3)
{
d = creat_states(node, i, j, 1, 0);
if (!if_repeat(d))
{
open.push_front(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
//右边
if (j + 1 >= 0 && j + 1 < 3)
{
d = creat_states(node, i, j, 0, 1);
if (!if_repeat(d))
{
open.push_front(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
//上
if (i - 1 >= 0 && i - 1 < 3)
{
d = creat_states(node, i, j, -1, 0);
if (!if_repeat(d))
{
open.push_front(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
//左
if (j - 1 >= 0 && j - 1 < 3)
{
d = creat_states(node, i, j, 0, -1);
if (!if_repeat(d))
{
open.push_front(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
nextStep();
}
int main()
{
states* node = new states();
node->DEPTH = 0;
node->ACTION = "初始状态";
node->PARENT_NODE = NULL;
cout << "请输入初始八数码状态图(必须包含数字0-8)";
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cin >> node->STATE[i][j];
}
}
cout << "请输入深度界限";
cin >> limit;
open.push_front(node);
nextStep();
destroy_close();
//cout << ++dept << endl;
}
结果:
BFS
(1)搜索产生的状态空间图
(2)程序清单
#include<string>
#include<list>
#include<set>
#include <iostream>
using namespace std;
struct states
{
int STATE[3][3] = { {1,2,3},{8,0,4},{7,6,5} };;//节点所表示状态的基本信息
states* PARENT_NODE = NULL;//指针域指向当前节点的父节点
string ACTION;//从父节点表示的状态转换为当前状态所使用的操作
int DEPTH;//当前节点在搜索树中的深度
double PATH_COST = 0;//从起始节点到当前节点的路径代价
bool operator ==(const states& p)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (STATE[i][j] != p.STATE[i][j])
return false;
}
}
return true;
}
};
ostream &operator <<(ostream&out, const states &node)
{
out << "----------------------" << endl;
out << "Action" << node.ACTION << endl;
out << "深度为" << node.DEPTH << endl;
out << "cost:" << node.PATH_COST << endl;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
out << node.STATE[i][j] << " ";
}
out << endl;
}
return out;
}
list<states*> open;//opem表
list<states*> close;//close表
int limit;//限制
states state_end;
//在父指针下判断其路劲是否有重复的
bool if_repeat(states* data)
{
list<states*>::iterator it;
for (it = open.begin(); it != open.end(); ++it)
{
if (**it == *data) return true;
}
for (it = close.begin(); it != close.end(); ++it)
{
if (**it == *data) return true;
}
return false;
}
states* creat_states(states* node, int i, int j, int dx, int dy)
{
states* data = new states();
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
data->STATE[i][j] = node->STATE[i][j];
}
}
data->STATE[i][j] = data->STATE[i + dx][j + dy];
data->STATE[i + dx][j + dy] = 0;
data->PARENT_NODE = node;
data->DEPTH = node->DEPTH + 1;
if (dx == -1) data->ACTION = "向上移动";
else if (dx == 1) data->ACTION = "向下移动";
else
{
if (dy == -1) data->ACTION = "向左移动";
else if (dy == 1) data->ACTION = "向右移动";
}
return data;
}
//int dept = 0;
//展示路径
void showpath(states* node)
{
if (node->PARENT_NODE != NULL)
{
showpath(node->PARENT_NODE);
//dept++;
}
cout << *node << endl;
}
/*void show_open()
{
if (!open.empty())
{
cout << "-----------showopen---------------" << endl;
list<states*>::iterator it;
for (it = open.begin(); it != open.end(); ++it)
{
cout << **it << endl;
}
cout << "-----------openend---------------" << endl << endl;
}
else
{
cout << "-------------open表为空----------" << endl << endl;
}
}
void show_close()
{
if (!close.empty())
{
cout << "-----------showclose-------------" << endl;
list<states*>::iterator it;
for (it = close.begin(); it != close.end(); ++it)
{
cout << **it << endl;
}
cout << "-----------closeend---------------" << endl << endl;
}
else cout << "------------close表为空------------" << endl << endl;
}
int i = 0;*/
//销毁
void destroy_close()
{
states * data;
while (!close.empty())
{
data = close.front();
close.pop_front();
delete data;
}
while (!open.empty())
{
data = open.front();
open.pop_front();
delete data;
}
}
void nextStep()
{
/*cout << "-------------------------------------------" << i << "-----------------------------------------------" << endl;
i++;
show_open();
show_close();*/
if (open.empty()) return;//open表为空
//否则将元素从open表中取出
states*node = open.front();
open.pop_front();
close.push_front(node);
if (node->DEPTH >= limit - 1)
{
nextStep();
return;
}
//找到那个0节点
int i;
int j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (node->STATE[i][j] == 0)
break;
}
if (j != 3) break;
}
//扩展node后面的所有节点
states*d;
//向四个方向扩展
//左
if (j - 1 >= 0 && j - 1 < 3)
{
d = creat_states(node, i, j, 0, -1);
if (!if_repeat(d))
{
open.push_back(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
//上
if (i - 1 >= 0 && i - 1 < 3)
{
d = creat_states(node, i, j, -1, 0);
if (!if_repeat(d))
{
open.push_back(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
//右边
if (j + 1 >= 0 && j + 1 < 3)
{
d = creat_states(node, i, j, 0, 1);
if (!if_repeat(d))
{
open.push_back(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
//下
if (i + 1 >= 0 && i + 1 < 3)
{
d = creat_states(node, i, j, 1, 0);
if (!if_repeat(d))
{
open.push_back(d);
if (*d == state_end)
{
d->ACTION = "终止节点";
cout << "----------------showanswer-------------" << endl;
showpath(d);
return;
}
}
else delete d;
}
nextStep();
}
int main()
{
states* node = new states();
node->DEPTH = 0;
node->ACTION = "初始状态";
node->PARENT_NODE = NULL;
cout << "请输入初始八数码状态图(必须包含数字0-8)";
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cin >> node->STATE[i][j];
}
}
cout << "请输入深度界限";
cin >> limit;
open.push_front(node);
nextStep();
destroy_close();
//cout << ++dept << endl;
}
结果:
A*算法
流程图:
程序清单:
#include<string>
#include<list>
#include <iostream>
using namespace std;
struct states
{
int STATE[3][3] = { {1,2,3},{8,0,4},{7,6,5} };;//节点所表示状态的基本信息
states* PARENT_NODE = NULL;//指针域指向当前节点的父节点
string ACTION;//从父节点表示的状态转换为当前状态所使用的操作
int DEPTH;//当前节点在搜索树中的深度
double PATH_COST = 0;//从起始节点到当前节点的路径代价
bool operator ==(const states& p)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (STATE[i][j] != p.STATE[i][j])
return false;
}
}
return true;
}
};
ostream &operator <<(ostream&out, const states &node)
{
out << "----------------------" << endl;
out << "Action" << node.ACTION << endl;
out << "深度为" << node.DEPTH << endl;
out << "cost:" << node.PATH_COST << endl;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
out << node.STATE[i][j] << " ";
}
out << endl;
}
return out;
}
struct statesComp
{
bool operator ()(states*& r1, states*& r2)
{
return r1->PATH_COST < r2->PATH_COST;
}
};
list<states*> open;//opem表
list<states*> close;//close表
int limit;//限制
states state_end;
//在父指针下判断其路劲是否有重复的
states* if_repeat(states* data)
{
list<states*>::iterator it;
for (it = open.begin(); it != open.end(); ++it)
{
if (**it == *data) return *it;
}
for (it = close.begin(); it != close.end(); ++it)
{
if (**it == *data) return *it;
}
return NULL;
}
int gn(states* states)
{
int sum = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
//sum = sum+abs(state_end.STATE[i][j] - states->STATE[i][j]);
if (states->STATE[i][j] != state_end.STATE[i][j]) sum++;
}
}
return sum;
}
states* creat_states(states* node, int i, int j, int dx, int dy)
{
states* data = new states();
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
data->STATE[i][j] = node->STATE[i][j];
}
}
data->STATE[i][j] = data->STATE[i + dx][j + dy];
data->STATE[i + dx][j + dy] = 0;
data->PARENT_NODE = node;
data->DEPTH = node->DEPTH + 1;
if (dx == -1) data->ACTION = "向上移动";
else if (dx == 1) data->ACTION = "向下移动";
else
{
if (dy == -1) data->ACTION = "向左移动";
else if (dy == 1) data->ACTION = "向右移动";
}
data->PATH_COST = data->DEPTH + gn(data);
return data;
}
//int dept = 0;
//展示路径
void showpath(states* node)
{
if (node->PARENT_NODE != NULL)
{
showpath(node->PARENT_NODE);
//dept++;
}
cout << *node;
}
//销毁
void destroy_close()
{
states * data;
while (!close.empty())
{
data = close.front();
close.pop_front();
delete data;
}
cout << endl << endl << endl;
while (!open.empty())
{
data = open.front();
open.pop_front();
delete data;
}
}
/*void show_open()
{
if (!open.empty())
{
cout << "------------------------showopen----------------------------" << endl;
list<states*>::iterator it;
for (it = open.begin(); it != open.end(); ++it)
{
cout << **it << endl;
}
cout << "------------------------openend-------------------------------" << endl << endl;
}
else
{
cout << "------------------------open表为空----------------------------" << endl << endl;
}
}
void show_close()
{
if (!close.empty())
{
cout << "-------------------------showclose----------------------------" << endl;
list<states*>::iterator it;
for (it = close.begin(); it != close.end(); ++it)
{
cout << **it << endl;
}
cout << "-------------------------closeend------------------------------" << endl << endl;
}
else cout << "------------------------close表为空---------------------------" << endl << endl;
}
int i = 0;*/
void nextStep()
{
/*cout << endl << endl;
cout << "-------------------------------------------" << i << "-----------------------------------------------" << endl;
i++;
show_open();
show_close();*/
if (open.empty()) return;//open表为空
//否则将元素从open表中取出
open.sort(statesComp());
states*node = open.front();
open.pop_front();
close.push_front(node);
if (*node == state_end)
{
cout << "-------------------------------------------showpath---------------------------------------------" << endl;
showpath(node);
return;
}
if (node->DEPTH >= limit - 1)
{
nextStep();
return;
}
//找到那个0节点
int i;
int j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (node->STATE[i][j] == 0)
break;
}
if (j != 3) break;
}
//扩展node后面的所有节点
states*d;
//向四个方向扩展
//左
if (j - 1 >= 0 && j - 1 < 3)
{
d = creat_states(node, i, j, 0, -1);
states* last = if_repeat(d);
if (last==NULL)
{
open.push_back(d);
}
else
{
if (last > d)
{
last->ACTION = d->ACTION;
last->DEPTH = d->DEPTH;
last->PARENT_NODE = d->PARENT_NODE;
last->PATH_COST = d->PATH_COST;
}
delete d;
}
}
//上
if (i - 1 >= 0 && i - 1 < 3)
{
d = creat_states(node, i, j, -1, 0);
states* last = if_repeat(d);
if (last == NULL)
{
open.push_back(d);
}
else
{
if (last > d)
{
last->ACTION = d->ACTION;
last->DEPTH = d->DEPTH;
last->PARENT_NODE = d->PARENT_NODE;
last->PATH_COST = d->PATH_COST;
}
delete d;
}
}
//右边
if (j + 1 >= 0 && j + 1 < 3)
{
d = creat_states(node, i, j, 0, 1);
states* last = if_repeat(d);
if (last == NULL)
{
open.push_back(d);
}
else
{
if (last > d)
{
last->ACTION = d->ACTION;
last->DEPTH = d->DEPTH;
last->PARENT_NODE = d->PARENT_NODE;
last->PATH_COST = d->PATH_COST;
}
delete d;
}
}
//下
if (i + 1 >= 0 && i + 1 < 3)
{
d = creat_states(node, i, j, 1, 0);
states* last = if_repeat(d);
if (last == NULL)
{
open.push_back(d);
}
else
{
if (last > d)
{
last->ACTION = d->ACTION;
last->DEPTH = d->DEPTH;
last->PARENT_NODE = d->PARENT_NODE;
last->PATH_COST = d->PATH_COST;
}
delete d;
}
}
nextStep();
}
int main()
{
states* node = new states();
node->DEPTH = 0;
node->ACTION = "初始状态";
node->PARENT_NODE = NULL;
cout << "请输入初始八数码状态图(必须包含数字0-8)";
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cin >> node->STATE[i][j];
}
}
cout << "请输入深度界限";
cin >> limit;
open.push_front(node);
nextStep();
destroy_close();
//cout << ++dept << endl;
}
结果: