题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1026
/*!这个问题一定要对has表映射的范围有控制,太小了不行*/
#include<stdio.h>
#include<string.h>
#define MAX 1000003
int dy[4]={-1,1,0,0},dx[4]={0,0,-1,1};//分别记录上、下、左、右四个方向
char op[5]="UDLR",step[MAX];
int st[MAX][9],head[MAX],next[MAX],up[MAX],father[MAX];
void init_look_uptabl(){
memset(next,0,sizeof(next));
memset(head,0,sizeof(head));
}
int has(int *s) {
int v = 0;
for(int i = 0; i < 9; i++) v = v * 10 + s[i];
return v % MAX;
}
int try_to_inser(int s) {
int h = has(st[s]);
int u = head[h];
while(u) {
if(memcmp(st[u], st[s], sizeof(st[s])) == 0) return 0;
u = next[u];
}
next[s] = head[h];
head[h] = s;
return 1;
}
int dfs(){
int fron=0,rear=1;
father[1]=0;
init_look_uptabl();
while(fron!=rear){
fron++;
int i;
for(i=0;i<9;i++) if(st[fron][i]==0) break;
int z=i;
int y=i/3,x=i%3;
for(i=0;i<4;i++){
int ty=y+dy[i],tx=x+dx[i];
if(ty>=0&&ty<3&&tx>=0&&tx<3){
rear++;
up[rear]=i;//up数组记录所走方向
father[rear]=fron;//father数组记录这个节点经过的上一节点的编号
int te[9];
memcpy(te,st[fron],sizeof(te));
te[z]=st[fron][ty*3+tx],te[ty*3+tx]=0;
memcpy(st[rear],te,sizeof(te));
if(try_to_inser(rear)==0) rear--;//判断这个状态之前是否访问过
}
}
}
return fron;
}
void print_path(int cur){
if(father[cur]!=0){
print_path(father[cur]);
printf("%c",op[up[cur]]);
}
}
int main(){
int t;
scanf("%d",&t);
int cas;
for(cas=1;cas<=t;cas++){
int i,j;
for(i=0;i<9;i++) scanf("%d",&st[1][i]);
int t=dfs();
printf("Puzzle #%d\n",cas);
int x,y;
for(i=0;i<3;i++){
for(j=0;j<3;j++){
printf("%d",st[t][i*3+j]);
if(j!=3) printf(" ");
}
printf("\n");
}
print_path(t);
printf("\n");
}
return 0;
}