八数码问题(BFS)

八数码问题解析(BFS搜索)
在一个3*3的棋盘上放置编号为1~8的8个方块,每个占一格,另外还有一格空格。与空格相邻的数字方块可以移动到空格里。指定初始
输入样例:
1 2 3 0 8 4 7 6 5
1 0 3 8 2 4 7 6 5
输出样例:
2
初始状态:

123
84
765

目标状态:

13
824
765

重点
1.利用康拓展开判重
2.合理利用队列
3.利用一维坐标和二维坐标

#include <iostream>
#include <queue>
const int LEN = 362880;//康拓展开的状态共有9!=362880种
using namespace std;

struct node {//用一维的数组记录一个状态
	int state[9];//记录状态
	int dis;//记录从初始到此状态需要多少步数
};


int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };//作为移动的四个方向

int start[9];//初始状态的位置
int goal[9];//目标状态的位置
//康拓展开需要用到的数据
long int factory[] = { 1,1,2,6,24,120,720,5040,40320,362880 };
long visited[LEN] = { 0 };
//利用康托展开判重
bool Cantor(int str[], int n) {
	long result = 0;//记录当前位置的编号
	for (int i=0;i<n;i++){
		int counted = 0;
		for (int j = i + 1; j < n; j++) {
			if (str[i] > str[j])//判断当前未出现的元素排在第几个
				counted++;
		}
		result += counted * factory[n - i - 1];
	}

	if (!visited[result]) {//如果当前状态并没有出现过
		//则将此状态标记,并返回1
		visited[result] = 1;
		return 1;
	}
	else {//如果出现过,则说明这个状态在之前就已经被走到了
		return 0;
	}

}


int dfs() {
	node head;
	memcpy(head.state, start, sizeof(head.state));//将初始状态的位置输入
	head.dis = 0;

	queue<node> q;//创建存储状态的队列

	q.push(head);//将初始状态加入

	while (!q.empty()){//当队列中没有任何状态时停止循环
		node head = q.front();//将队列中第一个状态取出

		if (head.state == goal) {
			return head.dis;//如果和目标状态相同则结束循环,将步数返回
		}
		//没有的话则继续循环,利用head将下一个状态推导出,并加入队列
		q.pop();

		int z = 0;//用于储存head中的0的一维位置
		for (int i = 0; i < 9; i++) {
			if (head.state[i] == 0) {
				z = i;
				break;
			}
		}
		//利用z将坐标转化为二维
		int x = z % 3;
		int y = z / 3;//此x,y坐标为原状态的0的二维坐标,利用这个坐标和dir数组中的四个方向,得出head状态的四种移动方式的结果

		for (int i = 0; i < 4; i++) {//将head移动后的4种状态依次列出
			int newx = x + dir[i][0];
			int newy = y + dir[i][1];
			int newz = newx + 3 * newy;//将新的坐标转化为一维,因为存储状态需要一维坐标
			//判断移动后是否越界
			if (newx >= 0 && newx < 3 && newy >= 0 && newy < 3) {
				node newnode;//没有越界,创建下一个状态

				memcpy(&newnode, &head, sizeof(node));//获得下一个状态需要得到上一个状态中的信息,然后通过新的坐标来更新上一个状态
				//上一个状态还要继续参加下一个循环,所以在此需要创建一个新的状态来获得老状态的信息,代替老状态完成更新,并添加到队列中
				//更新状态
				swap(newnode.state[z], newnode.state[newz]);//0的位置变换,直接交换即可
				newnode.dis++;//步数加一

				if (Cantor(newnode.state, 9)) {//利用康拓展开判重
					//若此状态没有出现过,则此状态是第一次出现
					q.push(newnode);//将此状态添加到队列中
				}

			}

		}

		return -1;//while循环结束,若执行到这一步,则说明将所有状态走完都没有得到目标状态,没有找到,返回-1

	}


}



int main() {
	//将初始位置和目标位置输入
	for (int i = 0; i < 9; i++)cin>> start[i];
	for (int i = 0; i < 9; i++)cin >> goal[i];
	int num = dfs();

	if (num == -1)cout << "Impossible" << endl;
	else cout << num << endl;

	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RE:0-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值