貌似当时都是双向BFS写的,现在自己写,就想先写单向的,然后就先是MLE,然后发现标记数组太大,于是学了一发康托展开,然后就是TLE,然后就发现需要记录状态,怎么记录呢,改了改发现就改成DFS的记忆化搜索了,然后又去学姿势,发现是从终点开始往回BFS,就能把所有情况都找到,并且BFS的过程中就可以记录下来,然后就AC了。
在这过程中也发现了一篇好文章,八数码八境界
广搜+哈希+打表 代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; #define maxs 362880 #define maxn 363000 const int aim = 123456780; char str[30]; int mark[maxn]; int fact[10]; int powint(int x, int a) { int ans = 1; for (int i = 0; i < a; ++i) ans *= x; return ans; } int cantor(int now) { int ans = 0; int num[9]; for (int i = 0; i < 9; ++i) { num[i] = now % 10; now /= 10; } for (int i = 0; i < 9; ++i) { int tmp = 0; for (int j = 0; j < i; ++j) { if (num[i] > num[j]) ++tmp; } ans += tmp*fact[i]; } return ans; } int read() { int re = 0; int n = strlen(str); for (int i = 0; i < n; ++i) { if (str[i] == 'x') re *= 10; if (str[i] >= '1'&&str[i] <= '9') re = re * 10 + str[i] - '0'; } return re; } int pos_0(int now) { int pos = -1; for (int i = 0; i < 9; ++i) { int tmp = now % 10; if (tmp == 0) { pos = i; break; } now /= 10; } return pos; } int down(int now) { int re = now, pos = pos_0(now); if (pos >= 3) { int pos2 = pos - 3; int x1 = re / powint(10, pos) % 10; int x2 = re / powint(10, pos2) % 10; re += (x2 - x1)*powint(10, pos); re += (x1 - x2)*powint(10, pos2); return re; } else return -1; } int up(int now) { int re = now, pos = pos_0(now); if (pos < 6) { int pos2 = pos + 3; int x1 = re / powint(10, pos) % 10; int x2 = re / powint(10, pos2) % 10; re += (x2 - x1)*powint(10, pos); re += (x1 - x2)*powint(10, pos2); return re; } else return -1; } int right(int now) { int re = now, pos = pos_0(now); if (pos % 3 != 0) { int pos2 = pos - 1; int x1 = re / powint(10, pos) % 10; int x2 = re / powint(10, pos2) % 10; re += (x2 - x1)*powint(10, pos); re += (x1 - x2)*powint(10, pos2); return re; } else return -1; } int left(int now) { int re = now, pos = pos_0(now); if ((pos + 1) % 3 != 0) { int pos2 = pos + 1; int x1 = re / powint(10, pos) % 10; int x2 = re / powint(10, pos2) % 10; re += (x2 - x1)*powint(10, pos); re += (x1 - x2)*powint(10, pos2); return re; } else return -1; } void BFS_init() { memset(mark, -1, sizeof(int)*maxn); queue<int> que; mark[cantor(aim)] = 0; que.push(aim); while (!que.empty()) { int now = que.front(); int cnt = mark[cantor(now)]; que.pop(); int u, d, l, r; u = up(now), d = down(now), l = left(now), r = right(now); if (u != -1) { int cu = cantor(u); if (mark[cu] == -1) { que.push(u); mark[cu] = cnt + 1; } } if (d != -1) { int cd = cantor(d); if (mark[cd] == -1) { que.push(d); mark[cd] = cnt + 1; } } if (l != -1) { int cl = cantor(l); if (mark[cl] == -1) { que.push(l); mark[cl] = cnt + 1; } } if (r != -1) { int cr = cantor(r); if (mark[cr] == -1) { que.push(r); mark[cr] = cnt + 1; } } } } int main() { //freopen("input.txt", "r", stdin); //康托展开+BFS+从目标往回搜索记录所有状态 or 双向BFS or A*搜索 fact[0] = 1; for (int i = 1; i < 10; ++i) fact[i] = i*fact[i - 1]; BFS_init(); while (gets(str)) { int now = read(); int ans = mark[cantor(now)]; if (ans >= 0) printf("%d\n", ans); else printf("unsolvable\n"); memset(str, 0, sizeof(str)); } //system("pause"); //while (1); return 0; }