这是经典的“八数码问题”。解法有很多,这里用的是状压BFS。
不过涉及一个有趣的东西:康托展开。
显然,我们可以把'x'当做0,这样每一个棋盘的状态对应的就是一个0~8的一个排列。
然后就是怎么压缩这个排列状态的问题。康托展开和其逆展开对此作了解答。
具体不难,就不介绍了。但是技不压身,我特地学习了一下,然后自己写了一个模板。就是一种编码方式,包括编码和解码,以后就可以直接用了。
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
using namespace std;
/*************************Cantor expansion***************************/
const int CACNTOR_MAX = 13;
int fac[CACNTOR_MAX] = {
1, 1, 2, 6, 24, 120,
720, 5040, 40320, 362880,
3628800, 39916800, 479001600
}; //fac list, fac[i] = i!, fac[max] = fac[12] = 479 001 600
//put x = a[0] * 1! + ... + a[bit-1] * bit! and put into array a[]
//0 <= a[i] <= i+1
//x count from 0
int decode(int a[], int bit, int x) {
bool tmp[CACNTOR_MAX] = {0};
//array[1,2,...bit]
//if U want to get [0, 1, ... , bit - 1]
//change
//a[i] = j
//to: a[i] = j - 1;
int res;
for (int i = 0; i < bit; ++i) {
a[i] = x / fac[bit - i - 1];
x %= fac[bit - i - 1];
int j = 1;
for (int l = 0; l <= a[i]; ++j)
if (!tmp[j]) ++l;
tmp[--j] = true;
a[i] = j - 1;
if (j == 1) res = i;
}
return res;
}
//use [0, 1, 2, ..., bit-1] or [1, 2, ..., bit]
//it all works.
int encode(int a[], int bit) {
int s = 0;
for (int i = 0; i < bit; ++i) {
int c = 0;
for (int j = i + 1; j < bit; ++j) {
c += a[j] < a[i];
}
s += c * fac[bit-i-1];
}
return s;
}
/********************************************************************/
const int MAX = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 + 7;
char move[MAX];
int father[MAX];
bool vis[MAX];
void debug(int status) {
int a[10];
decode(a, 9, status);
for (int i = 0; i < 9; ++i) {
printf("%d ", a[i]);
}
puts("");
}
int BFS(int s, int t) {
memset(vis, false, sizeof(vis));
memset(father, -1, sizeof(father));
queue<int> Q;
Q.push(s);
vis[s] = true;
int now, next, a[9];
while (!Q.empty()) {
now = Q.front();
Q.pop();
if (now == t) return t;
int pos = decode(a, 9, now);
//u: up
if (pos > 2) {
swap(a[pos], a[pos - 3]);
next = encode(a, 9);
if (!vis[next]) {
vis[next] = true;
father[next] = now;
move[next] = 'u';
Q.push(next);
//debug(next);
}
swap(a[pos], a[pos - 3]);
}
//d
if (pos < 6) {
swap(a[pos], a[pos + 3]);
next = encode(a, 9);
if (!vis[next]) {
vis[next] = true;
father[next] = now;
move[next] = 'd';
Q.push(next);
//debug(next);
}
swap(a[pos], a[pos + 3]);
}
//l
if (pos % 3) {
swap(a[pos], a[pos - 1]);
next = encode(a, 9);
if (!vis[next]) {
vis[next] = true;
father[next] = now;
move[next] = 'l';
Q.push(next);
//debug(next);
}
swap(a[pos], a[pos - 1]);
}
//r
if ((pos % 3) < 2) {
swap(a[pos], a[pos + 1]);
next = encode(a, 9);
if (!vis[next]) {
vis[next] = true;
father[next] = now;
move[next] = 'r';
Q.push(next);
//debug(next);
}
swap(a[pos], a[pos + 1]);
}
}
return -1;
}
int main() {
int a[10];
char ch;
while (~scanf(" %c", &ch)) {
a[0] = ch == 'x' ? 0 : ch - '0';
for (int i = 1; i < 9; ++i) {
scanf(" %c", &ch);
a[i] = ch == 'x' ? 0 : ch - '0';
}
int s = encode(a, 9);
for (int i = 0; i < 9; ++i) {
a[i] = (i + 1) % 9;
}
int t = encode(a, 9);
int ret = BFS(s, t);
if (ret == -1) {
puts("unsolvable");
continue;
}
//printf("s = %d, t = %d\n", s, t);
int p = t;
stack<char> S;
while (!S.empty()) S.pop();
while (p != -1) {
S.push(move[p]);
p = father[p];
}
S.pop();
while (!S.empty()) {
putchar(S.top());
S.pop();
}
putchar('\n');
}
return 0;
}