在一个 $3×3$ 的网格中,$1 \sim 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
把 x
与上下左右方向数字交换的行动记录为 u
、d
、l
、r
。
现在,给你一个初始网格,请你通过最少的移动次数,得到正确排列。
输入格式
输入占一行,将 $3×3$ 的初始网格描绘出来。
例如,如果初始网格如下所示:
1 2 3
x 4 6
7 5 8
则输入为:1 2 3 x 4 6 7 5 8
输出格式
输出占一行,包含一个字符串,表示得到正确排列的完整行动记录。
如果答案不唯一,输出任意一种合法方案即可。
如果不存在解决方案,则输出 unsolvable
。
输入样例:
2 3 4 1 5 x 7 6 8
输出样例
ullddrurdllurdruldr
#include <queue>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
int num;
string A, B;
int f(string state)
{
int res = 0;
for (int i = 0; i < state.size(); i ++)
{
if (state[i] != 'x')
{
int t = state[i] - '1';
res += abs(t / 3 - i / 3) + abs(i % 3 - t % 3);
}
}
return res;
}
void bfs()
{
unordered_map<string, int> d;
unordered_map<string, pair<char, string>> pre;
priority_queue<pair<int, string>, vector<pair<int, string>>, greater<pair<int, string>>> heap;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1};
char ix[] = "uldr";
d[A] = 0;
heap.push({f(A), A});
while (heap.size())
{
auto t = heap.top();
heap.pop();
if (t.second == B) break;
int pos = t.second.find('x');
for (int i = 0; i < 4; i ++)
{
string str = t.second;
int x = pos / 3 + dx[i], y = pos % 3 + dy[i];
if (x < 0 || x > 2 || y < 0 || y > 2) continue;
swap(str[x * 3 + y], str[pos]);
if (!d.count(str) || d[str] > d[t.second] + 1)
{
d[str] = d[t.second] + 1;
pre[str] = {ix[i], t.second};
heap.push({d[str] + f(str), str});
}
}
}
string ans;
while (B != A)
{
ans += pre[B].first;
B = pre[B].second;
}
reverse(ans.begin(), ans.end());
cout << ans;
}
int main()
{
string res;
for (int i = 0; i < 9; i ++)
{
char s;
cin >> s;
A += s;
if (s != 'x') res += s;
}
B = "12345678x";
for (int i = 0; i < res.size(); i ++)
for (int j = i + 1; j < res.size(); j ++)
if (res[i] > res[j])
num ++;
if (num & 1) puts("unsolvable");
else bfs();
return 0;
}