题意:同样的八数码问题。
思路:因为是多组测试,如果每次都来一遍bfs的话,一定会超时的。我们可以注意到,因为终点给定,我们可以反向求出其他状态到终点的路径。这个样子的话,判重只能用康拓展开了。
代码如下:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <set>
using namespace std;
typedef int state[9];
int dx[] = {0,0,-1,1};
int dy[] = {1,-1,0,0};
char dir[] = {'l','r','d','u'};
int fact[9];
const int MAX = 400000;
state que[MAX],en,st;
int fa[MAX],path[MAX],d[MAX];
bool vis[400000];
char str[50];
int cantor(state & t)
{
int v = 0;
for(int i = 0; i < 9; ++i){
int cnt = 0;
for(int j = i + 1; j < 9; ++j)
if(t[j] < t[i]) cnt++;
v += fact[8-i] * cnt;
}
return v;
}
bool insert(int v)
{
if(vis[v]) return 0;
return vis[v] = true;
}
void init()
{
fact[0] = 1;
for(int i = 1; i < 9; ++i)
fact[i] = fact[i-1] * i;
memset(fa,-1,sizeof(fa));
}
void bfs()
{
int front = 0, tail = 0;
memcpy(&que[tail],&st,sizeof(st)),tail++;
while(front < tail){
state & t = que[front];
int vt = cantor(t);
int z;
for(z = 0; z < 9; ++z) if(!t[z]) break;
int x = z / 3, y = z % 3;
for(int i = 0; i < 4; ++i){
int nx = x + dx[i], ny = y + dy[i];
int nz = 3 * nx + ny;
if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){
state & s = que[tail];
memcpy(&s,&t,sizeof(t));
swap(s[z],s[nz]);
int vs = cantor(s);
if(insert(vs)){
fa[vs] = vt;
d[vs] = i;
tail++;
}
}
}
front++;
}
}
int main(void)
{
//freopen("input.txt","r",stdin);
init();
for(int i = 0; i < 8; ++i) st[i] = i+1;
st[8] = 0;
bfs();
while(~scanf("%s",str)){
if(!sscanf(str,"%d",&en[0])) en[0] = 0;
for(int i = 1; i < 9; ++i){
scanf("%s",str);
if(!sscanf(str,"%d",&en[i]))
en[i] = 0;
}
int v = cantor(en);
if(fa[v] == -1)
puts("unsolvable");
else{
for(;v != 46233; v = fa[v])
putchar(dir[d[v]]);
puts("");
}
}
return 0;
}