八数码问题-双向bfs

如代码,注释的很清楚了
单向的还可以看看这个https://blog.csdn.net/qq_42971794/article/details/87869292
以下是参考上面连接的双向

#include<iostream>
#include<algorithm>
#include<queue>	
#include<map>
#include<string>
using namespace std;
int dr[][2] = { 0,1,0,-1,1,0,-1,0 };
queue<int> q1, q2;
map<int, int> c1;  //记录是否走过这个状态,避免重复,
map<int, int> c2;  //记录到这个状态需要走多少步
int init(int map[3][3]) { 
	int ans = 0;
	for (int i = 0; i <3; ++i) {
		for (int j = 0; j<3; ++j) {
			ans = ans * 10 + map[i][j];
		}
	}
	return ans;
}
int main() {
	int first;
	int ans;
	int mapp[3][3];
	for (int i = 0; i < 3; ++i)
		for (int j = 0; j < 3; ++j)
			cin >> mapp[i][j];
	first = init(mapp);
	for (int i = 0; i < 3; ++i)
		for (int j = 0; j < 3; ++j)
			cin >> mapp[i][j];
	ans = init(mapp);
	q1.push(first);
	c1[first] = 1;//说明first这个状态访问过,以后遇到就不用继续 访问了。 并且用1表示是从正向bfs访问的。
	c2[first] = 0;//first是初始状态,只需要0步就可以到达。
	q2.push(ans);
	c1[ans] = 2;//2表示是从后面开始访问得到的结点。
	c2[ans] = 0;//同上
	bool is;
	while (!q1.empty() || !q2.empty()) {
		int begin, x, y;  //x,y表示空格的位置
		if (q1.size() < q2.size() || q2.empty()) {
			begin = q1.front();
			q1.pop();
			is = true;
		}
		else {
			begin = q2.front();
			q2.pop();
			is = false;
		}
		int k = begin;
		for (int i = 2; i >= 0; --i)
			for (int j = 2; j >= 0; --j)
			{
				mapp[i][j] = k % 10;
				k /= 10;
				if (mapp[i][j] == 0) {
					x = i;
					y = j;
				}
			}
		for (int i = 0; i < 4; ++i) {
			int x_new = x + dr[i][0];
			int y_new = y + dr[i][1];
			if (x_new >= 0 && x_new < 3 && y_new >= 0 && y_new < 3) {
				swap(mapp[x][y], mapp[x_new][y_new]);
				int temp = init(mapp);
				if (c1[temp] == c1[begin])  //说明与之前的状态有重复,故不再继续以此状态bfs;
				{
					swap(mapp[x][y], mapp[x_new][y_new]);
					continue;
				}
				if (c1[temp] + c1[begin] == 3) {
					cout << c2[temp] + c2[begin] + 1;
					return 0;
				}
				c2[temp] = c2[begin] + 1;   //否则就继续bfs,则多走了1步
				c1[temp] = c1[begin];       //按照之前的bfs标记。
				if (is == true) {
					q1.push(temp);
				}
				else q2.push(temp);
				swap(mapp[x][y], mapp[x_new][y_new]);   //回到循环开始的状态,继续所有该层。这个别忘记了!一定要复原。
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值