在一个 3×33×3 的网格中,1∼81∼8 这 88 个数字和一个
X
恰好不重不漏地分布在这 3×33×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×33×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
性质1:将八书码排成一列,若他们的逆序对数目为偶数说明有解,否则无解
{
证明:如图:
}
估价函数:每个数字到其正确位置的曼哈顿距离之和即为估价函数
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define x first
#define y second
using namespace std;
typedef pair<int, string> PIS;
typedef pair<char, string> PCS;
const int N = 10;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
char op[5] = {'u', 'r', 'd', 'l'};//一次进行上右下左四个操作
int f(string state)//计算估价函数即计算每个数字到其正确位置的曼哈顿距离之和
{
int res = 0;
for (int i = 0; i < state.size(); i ++ )
{
int t = state[i] - '1';
res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);
}
return res;
}
void bfs(string start)
{
string lasts = "12345678x";//定义目标序列
priority_queue<PIS, vector<PIS>, greater<PIS>> heap;
unordered_map<string, PCS> pre;//记录从哪个步骤转移过来已经相应操作
unordered_map<string, int> dist;
heap.push({f(start), start});
dist[start] = 0;
while (heap.size())
{
auto t = heap.top();
heap.pop();
int x, y;
string state = t.y;
int step = dist[state];
if (state == lasts) break;
for (int i = 0; i < state.size(); i ++ )//找出当前坐标
{
if (state[i] == 'x')
{
x = i / 3;
y = i % 3;
break;
}
}
string temp = state;
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) continue;
swap(state[a * 3 + b], state[x * 3 + y]);//进行上右下左移动的操作
if (!dist.count(state) || dist[state] > step + 1)//若次状态之前未出现过,或者出现过但所需步骤大于当前步骤
{
dist[state] = step + 1;
pre[state] = {op[i], temp};
heap.push({dist[state] + f(state), state});
}
swap(state[a * 3 + b], state[x * 3 + y]);//返回原状好进行下一次操作
}
}
string res;
while (start != lasts)//从末尾到开始输出操作
{
res += pre[lasts].x;
lasts = pre[lasts].y;
}
reverse(res.begin(), res.end());
cout << res << endl;
}
int main()
{
string start, seq;
for (int i = 0; i < 9; i ++ )
{
char c;
cin >> c;
start += c;
if (c != 'x') seq += c;
}
int t = 0;
for (int i = 0; i < seq.size(); i ++ )//求逆序对的数目
for (int j = i + 1; j < seq.size(); j ++ )
if (seq[i] > seq[j]) t ++ ;
if (t & 1) puts("unsolvable");
else bfs(start);
return 0;
}