c++解决8数码问题

问题简介:
所谓八数码问题是指这样一种游戏:将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放在一块3×3的数码盘上。放牌时要求不能重叠。于是,在 3×3的数码盘上出现了一个空格。现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,将任意摆放的数码盘逐步摆成某种特殊的排列。如下图表示了 一个具体的八数码问题求解。
 

问题分析:

这个路径搜索问题可以引申为构建一颗四叉树的问题。

把九宫格信息保存在一个节点类里,节点类具有一个父类指针和四个孩子指针。树的根节点存储了初始状态,寻找最短路径的过程就是通过宽度优先不断扩展四叉树的叶节点的过程。

下面附上我的代码

#include
#include
#include
using namespace std;
class Node {
public:
	int Nine[3][3];
	Node *child1,*child2,*child3,*child4;
	Node* parent;
	Node(int a[3][3], Node* p=NULL,Node* c1 = NULL,Node* c2 = NULL,Node* c3=NULL,Node* c4=NULL)
	{
		for (int i = 0; i < 3; i++) 
			for (int j = 0; j < 3; j++)
				Nine[i][j] = a[i][j];
		parent = p;
		child1 = c1;
		child2 = c2;
		child3 = c3;
		child4 = c4;
	}
	friend bool operator==(Node a, Node b)//重载==,比较两个九宫格是否相同
	{
		bool flag = 1;
		for (int i = 0; i < 3; i++)
			for (int j = 0; j < 3; j++)
				if (a.Nine[i][j] != b.Nine[i][j])return false;
		return true;
	}
};
class EightPuzzle {//8数码问题
private:
	Node* start;//初始状态
	Node* target;//目标状态
	queue dict;//BFS中存储未遍历过的节点
	stack shortpath;//存储最短路径
public:
	EightPuzzle(int a[3][3], int b[3][3]) { start = new Node(a); target = new Node(b); }
	bool compare(Node* root,Node p);//搜索当前准备添加的新路径是否已经出现过
	void grow(Node *leaf);//从叶节点扩展新的不重复的路径
	void swap(int& a, int& b);
	void BFS();
	void print();
	bool isexist();//检测是否有路径能到达目标状态
};
bool EightPuzzle::isexist() {
	int a = 0, b = 0;
	for (int i = 0; i < 9; i++)
		for (int j = 0; j < i; j++)
			if (start->Nine[j] > start->Nine[i])a++;
	for (int i = 0; i < 9; i++)
		for (int j = 0; j < i; j++)
			if (target->Nine[j] > target->Nine[i])b++;
	if (a % 2 == b % 2)return 1;
	else return 0;
}
bool EightPuzzle::compare(Node* root,Node p){
	if (root!=NULL &&*root== p)return 1;
	if (root->child1 != NULL)compare(root->child1, p);
	if (root->child2 != NULL)compare(root->child2, p);
	if (root->child3 != NULL)compare(root->child3, p);
	if (root->child4 != NULL)compare(root->child4, p);
	return 0;
}
void EightPuzzle::swap(int& a, int& b) {
	int tmp = a;
	a = b; 
	b = tmp;
}
void EightPuzzle::grow(Node* leaf) {
	int a[3][3];
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			 a[i][j]= leaf->Nine[i][j];
	int x = 0, y = 0;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (a[i][j] == 0) { x = i; y = j; }
		}
	}
	if ((x - 1) >= 0)
	{
		Node p = *leaf;
		swap(p.Nine[x][y], p.Nine[x - 1][y]);
		if (!compare(start, p))
		{
			Node* q = new Node(p); leaf->child1 = q; q->parent = leaf; dict.push(q);
		}
	}
	if (x + 1 <= 2)
	{
		Node p = *leaf;
		swap(p.Nine[x][y], p.Nine[x + 1][y]);
		if (!compare(start, p))
		{
			Node* q = new Node(p); leaf->child2 = q; q->parent = leaf; dict.push(q);
		}
	}
	if (y - 1 >= 0)
	{
		Node p = *leaf;
		swap(p.Nine[x][y], p.Nine[x][y-1]);
		if (!compare(start, p))
		{
			Node* q = new Node(p); leaf->child3 = q; q->parent = leaf; dict.push(q);
		}
	}
	if (y + 1 <= 2)
	{
		Node p = *leaf;
		swap(p.Nine[x][y], p.Nine[x][y+1]);
		if (!compare(start, p))
		{
			Node* q = new Node(p); leaf->child4 = q; q->parent = leaf; dict.push(q);
		}
	}
}
void EightPuzzle::BFS() {
	if (isexist() == 0) { cout << "没有移动方法能从起始状态目标状态!"; exit(1); }
	else { cout << "移动步骤如下:\n"; }
	Node *p = start;
	dict.push(p);
	while (!(*p == *target))
	{
		dict.pop();
		grow(p);
		p = dict.front();
	}
	target = p;
	Node *q = target;
	while (q != NULL)
	{
		shortpath.push(*q);
		q = q->parent;
	}
}
void EightPuzzle::print() {
	while (!shortpath.empty()) {
		Node p = shortpath.top();
		shortpath.pop();
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++)
				cout << p.Nine[i][j]<<' ';
			cout << endl;
		}
		cout << endl;
	}
}
int main() {
	int a[3][3] ;
	int b[3][3] ;
	cout << "以九宫格形式输入初始状态:\n";
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++)
			cin >> a[i][j];
	cout<< "以九宫格形式输入最终状态:\n";
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++)
			cin >> b[i][j];
	EightPuzzle test(a, b);
	test.BFS();
	test.print();
	return 0;
}

 

你可能感兴趣的:(c++)