0%

八数码

有一个 3*3 的棋盘,其中有 1-9 共 9 个数字,0 表示空格,
其他的数字可以和 0 交换位置。求由初始状态到达目标状态

目标状态

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

如果问题无解,输出 unsolvable。
如果有解,则输出空格的移动序列。
u 表示将空格向上移,d 表示将空格向下移,l 表示左移,r 表示右移。

思路

两个unordered_map容器d和dd,分别用于保存状态到步数的映射和状态到移动方向的映射。同时还定义了一个unordered_map容器path,用于保存状态到前一个状态的映射,以便在找到解后可以回溯路径。

首先,从输入中读取初始状态start,并初始化目标状态e为固定的”123456780”。

接下来,调用bfs函数执行广度优先搜索。在搜索过程中,使用unordered_map容器d来保存已经搜索过的状态及其对应的步数。使用unordered_map容器dd来保存已经搜索过的状态及其对应的移动方向(用数字表示,0表示向下移动,1表示向上移动,2表示向左移动,3表示向右移动)。使用queue容器q来保存待搜索的状态。

在搜索过程中,首先将初始状态start入队,并将其对应的步数d[start]设为0。然后进入循环,直到队列为空。在每一次循环中,取出队列的头部状态t,并找到空格字符’0’的位置pos。如果当前状态t等于目标状态e,说明已经找到解,返回步数d[t]。

接下来,根据空格字符的位置pos,计算其所在的行x和列y。然后使用循环遍历四个移动方向,分别计算新的行坐标xx和列坐标yy。如果移动后的位置(xx, yy)在合法范围内,即xx在0到2之间,yy在0到2之间,则进行移动操作。将状态t中的空格字符’0’和位置(xx, yy)上的字符进行交换,得到新的状态new_state。如果新状态new_state在d中没有出现过(即未被访问过),则将其加入队列q中,并更新d[new_state]为d[t]+1,表示从初始状态到达新状态的步数。同时将移动方向i保存到dd[new_state]中,表示从前一个状态移动到新状态的方向。并将路径信息保存到path[new_state]中,表示新状态的前一个状态是t。

完成搜索后,如果没有找到解(d[t]仍然为0),或者找到解的步数为-1,则输出”unsolvable”。否则,调用ff函数进行路径回溯,从目标状态e开始,根据dd和path的信息逆序输出移动方向,即为从初始状态到目标状态的移动序列。

AC代码

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<unordered_map>

using namespace std;

int tt;
string start, e;
int dx[4] = { 1,-1,0,0 }, dy[4] = { 0,0,-1,1 };//下,上,左,右;
unordered_map<string, int> d,dd;
unordered_map<string, string> path;

int bfs()
{

queue<string> q;

d[start] = 0;
dd[start] = -1;
q.push(start);

path[start] = "xxxx";

while (!q.empty())
{
string t = q.front();
q.pop();

int pos = t.find('0');

if (t == e)return d[t];

//cout << t << endl;

string str = t;

int x = pos / 3, y = pos % 3;

for (int i = 0; i <= 3; i++)
{
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 0 && xx <= 2 && yy >= 0 && yy <= 2)
{
swap(t[pos], t[(xx) * 3 + yy]);
if (!d.count(t))
{
dd[t] = i;
path[t] = str;
q.push(t);
d[t] = d[str] + 1;
}
swap(t[pos], t[(xx) * 3 + yy]);
}
}

}
return -1;
}

void ff()
{
string a = "123456780";
string dis;

while (dd[a] != -1)
{
if (dd[a] == 0) dis += 'd';
if (dd[a] == 1) dis += 'u';
if (dd[a] == 2) dis += 'l';
if (dd[a] == 3) dis += 'r';

a = path[a];
}

reverse(dis.begin(), dis.end());

cout << dis;
}


int main()
{

int i = 1;
while (i <= 9)
{
char c;
cin >> c;
if (c != ' ')
{
if (c == 'x')
{
start += '0';
}
else
start += c;
i++;
}

}

e = "123456780";

int t = bfs();

if (t == -1||t == 0 )
cout << "unsolvable";
else ff();
return 0;
}
-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道