题目描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
在一个 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

题解

点击查看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <cstring>
#include <unordered_map>
#include <queue>

using namespace std;

int bfs(string start){
string end = "12345678x";//终点字符串

unordered_map <string, int> d;
queue<string> q;
//将初始状态入队,距离为0
q.push(start);
d[start] = 0;
//方位数组
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};
//当队列不为空的时候,取出队头元素,然后拓展
while(q.size()){
auto t = q.front();
q.pop();

int distance = d[t];
if(t == end) return distance;
//将字符串转换成矩阵
int k = t.find('x');//获取x的下标
int x = k / 3, y = k % 3;//x,y即为3x3数组中x的坐标
//拓展
for(int i = 0; i < 4; ++i){
int a = x + dx[i], b = y + dy[i];
//如果没有越界,那就交换
if(a >= 0 && a < 3 && b >= 0 && b < 3){
swap(t[k], t[a * 3 + b]);//a * 3 + b即为a, b在字符串中的下标
if(!d.count(t)){//如果距离数组d中没有t字符串,即交换后的状态
d[t] = distance + 1;//那就入队并且记录距离
q.push(t);
}
swap(t[k], t[a * 3 + b]);//恢复状态,因为要遍历上下左右四个方向
}
}
}
return -1;
}

int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);

string start;

for(int i = 0; i < 9; ++i){
char c;
cin >> c;
start += c;
}

cout << bfs(start) << endl;

return 0;
}