貌似当时都是双向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;
}