八数码问题

实验二 八数码问题
一、实验目的
本实验课程是计算机、智能、物联网等专业学生的一门专业课程,通过实验,帮助学生更好地掌握人工智能相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对智能程序、智能算法等有比较深入的认识。
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;
}

结果:
在这里插入图片描述

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值