845. 八数码

在一个3×3的网格中,1~8这8个数字和一个“X”恰好不重不漏地分布在这3×3的网格中。

例如:

1 2 3
X 4 6
7 5 8

在游戏过程中,可以把“X”与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 X

例如,示例中图形就可以通过让“X”先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

1 2 3 1 2 3 1 2 3 1 2 3
X 4 6 4 X 6 4 5 6 4 5 6
7 5 8 7 5 8 7 X 8 7 8 X

现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。
输入格式

输入占一行,将3×3的初始网格描绘出来。

例如,如果初始网格如下所示:
1 2 3

x 4 6

7 5 8

则输入为:1 2 3 x 4 6 7 5 8
输出格式

输出占一行,包含一个整数,表示最少交换次数。

如果不存在解决方案,则输出”-1”。
输入样例:

2 3 4 1 5 x 7 6 8

输出样例

19

分析

首先这是一个求最短路径的问题,那么第一个想到的肯定是BFS,要用BFS先要解决存储结构的问题

1.这里是一个3*3的格子,我们如果用一个三维数组取存状态的话肯定是不方便的,而且queue也无法存这样的数组,所以这里要转换成字符串,然后用一个unordered_map来存每一个字符串的的变换次数,这样决解了数据存储问题

2.之后就是如何完成状态的改变,对于一个字符串中的字符,先用find函数找到下标,之后横坐标就是idx/3;中坐标就是idx%3,在判断上下左右是否可以,就可以了

3.还有一个问题,就是不能用map!!,map的查询速度远不及unordered_map快,所以用map会超时。

代码

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int dx[] = {
      -1,0,0,1 };
int dy[] = {
      0,-1,1,0 };
int bfs(string st) {
     
	string en = "12345678x";
	queue<string> q;
	unordered_map<string, int> mp;
	q.push(st);
	mp[st] = 0;
	while (!q.empty()) {
     
		string t = q.front();
		int distance = mp[t];
		q.pop();
		if (t == en) {
     
			return mp[t];
		}
		int idx = t.find('x');
		int x = idx / 3;
		int y = idx % 3;
		for (int i = 0; i < 4; i++) {
     
			int a = x + dx[i];
			int b = y + dy[i];
			if (a >= 0 && a < 3 && b >= 0 && b < 3) {
     
				swap(t[idx], t[a * 3 + b]);//用a*3+b来把坐标转换一维的
				if (!mp.count(t)) {
     
					q.push(t);
					mp[t] = distance + 1;
				}
				swap(t[idx], t[a * 3 + b]);//不要忘记换回去
			}
		}
	}
	return -1;
}
int main() {
     
	string s;
	for (int i = 0; i < 9; i++) {
     
		char c;
		cin >> c;
		s += c;
	}
	cout << bfs(s) << endl;
}

你可能感兴趣的:(ACwing,BFS)