***> 题目来源:***VJ- I - Eight II
Eight-puzzle, which is also called “Nine grids”, comes from an old
game.In this game, you are given a 3 by 3 board and 8 tiles. The tiles are
numbered from 1 to 8 and each covers a grid. As you see, there is a
blank grid which can be represented as an ‘X’. Tiles in grids having a
common edge with the blank grid can be moved into that blank grid.
This operation leads to an exchange of ‘X’ with one tile.We use the symbol ‘r’ to represent exchanging ‘X’ with the tile on its
right side, and ‘l’ for the left side, ‘u’ for the one above it, ‘d’
for the one below it.
The problem is to operate an operation list of ‘r’, ‘u’, ‘l’, ‘d’ to
turn the state of the board from state A to state B. You are required
to find the result which meets the following constrains:
- It is of minimum length among all possible solutions.
- It is the lexicographically smallest one of all solutions of minimum length. Input The first line is T (T <= 200), which means the
number of test cases of this problem.The input of each test case consists of two lines with state A
occupying the first line and state B on the second line. It is
guaranteed that there is an available solution from state A to B.
Output For each test case two lines are expected.The first line is in the format of “Case x: d”, in which x is the case
number counted from one, d is the minimum length of operation list you
need to turn A to B. S is the operation list meeting the constraints
and it should be showed on the second line.
Sample Input
2
12X453786
12345678X
564178X23
7568X4123
Sample Output
Case 1: 2
dd
Case 2: 8
urrulldr
代码:
/**
* bfs() + Cantor + 预处理 + 映射
*/
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e8;
const int N = 4e5;
int n, m;
char End[9][10] = {"X12345678", "1X2345678", "12X345678",
"123X45678", "1234X5678", "12345X678",
"123456X78", "1234567X8", "12345678X"};
char step[] = "dlru"; // 字典序小的先遍历
int opx[4] = {1, 0, 0, -1};
int opy[4] = {0, -1, 1, 0};
int cantor[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
int vis[9][N]; // 标记走过的地方
int pre[9][N]; // 记录
struct node {
int num[9]; //八位数
int ok; //状态(康托展开值)
int pos; // x的位置
};
// 计算cantor值
int Cantor(int *s) {
int sum = 0;
for (int i = 0; i < 9; i++) {
int num = 0;
for (int j = i + 1; j < 9; j++) {
if (s[i] > s[j])
num++;
}
sum += num * cantor[8 - i];
}
return sum;
}
void bfs(node x, int k) {
queue<node> q;
q.push(x);
vis[k][x.ok] =
1; //这个是初始化的值并不是真正走的值所以上面输出的时候是从倒数第二个开始输出
while (!q.empty()) {
node now = q.front();
q.pop();
int x = now.pos / 3;
int y = now.pos % 3;
for (int i = 0; i < 4; i++) {
int xx = x + opx[i];
int yy = y + opy[i];
if (xx >= 0 && xx < 3 && yy >= 0 && yy < 3) {
node next = now;
swap(next.num[now.pos], next.num[xx * 3 + yy]);
next.ok = Cantor(next.num);
if (vis[k][next.ok] == -1) {
next.pos = xx * 3 + yy;
vis[k][next.ok] = i; //代表通过i方向的移动到达k这类中的v.ok状态
pre[k][next.ok] = now.ok; //记录这种状态的前一种状态
q.push(next);
}
}
}
}
}
void init(char *s, int k) {
node u;
for (int i = 0; i < 9; i++) {
if (s[i] == 'X') {
u.num[i] = 0;
u.pos = i;
} else
u.num[i] = s[i] - '0';
}
u.ok = Cantor(u.num);
bfs(u, k); // 每一种都bfs()
}
void printWay(int ok, int k) {
string ans;
while (ok != -1) {
ans += step[vis[k][ok]];
ok = pre[k][ok];
//往上找
}
printf("%d\n", ans.size() - 1);
for (int i = ans.size() - 2; i >= 0; i--) {
printf("%c", ans[i]);
}
printf("\n");
}
int main(int argc, char const *argv[]) {
char tmp[15]; // 用来映射
int temp[N];
memset(vis, -1, sizeof(vis)); // 初始化
memset(pre, -1, sizeof(pre));
for (int i = 0; i < 9; i++) {
init(End[i], i);
} // 全区来一遍
int t;
cin >> t;
int cas = 0;
while (t--) {
char Start[10];
scanf("%s", Start);
int cnt = 1;
int k;
for (int i = 0; i < 9; i++) {
if (Start[i] == 'X') {
tmp[0] = 0;
k = i;
} else {
tmp[Start[i] - '0'] = cnt++;
}
}
char End[10];
scanf("%s", End);
for (int i = 0; i < 9; i++) {
if (End[i] == 'X') {
temp[i] = tmp[0];
} else {
temp[i] = tmp[End[i] - '0'];
}
}
int ok = Cantor(temp);
printf("Case %d: ", ++cas);
printWay(ok, k);
}
return 0;
}