这个题跟汝佳君书上的代码差不多,不同的是,这个题需要bfs到所有状态均访问过,并且此题要求打印具体的移动方案,所以用一个结构体来存移动的步数,以及具体的移动方案。
另外原先书上的代码需要改动return的条件,即直到队列为空才跳出,并且返回的值是front-1。
好题啊!!!
#include<stdio.h>
#include<string.h>
typedef char state[10];
const int MAX=1000000;
const int MAXHASH=1000003;
state sta[MAX];
const int MA=100;
//结构体存储节点的距离以及移动方案
struct point
{
int dis;
char road[MA];
}p[MAX];
int head[MAXHASH],next[MAX];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
char ch[][2]={"U","D","L","R"};
int Hash(char s[])
{
int v=0;
for(int i=0;i<9;i++) v=v*10+s[i];
return v%MAXHASH;
}
//哈希判重
int notsame(int s)
{
int h=Hash(sta[s]);
int u=head[h];
while(u)
{
if(memcmp(sta[u],sta[s],sizeof(sta[s]))==0) return 0;
u=next[u];
}
next[s]=head[h];
head[h]=s;
return 1;
}
int bfs()
{
int fron=1,rear=2;
memset(head,0,sizeof(head));
while(fron<rear)
{
state& s = sta[fron];
int z;
for(z=0;s[z]!=0&&z<9;z++);
//printf("%d\n",z);
int x=z/3,y=z%3;
for(int i=0;i<4;i++)
{
int tmpx= x+dx[i];
int tmpy= y+dy[i];
int tmpz=tmpx*3+tmpy;
if(tmpx>=0&&tmpx<3&&tmpy>=0&&tmpy<3)
{
state& t=sta[rear];
memcpy(&t,&s,sizeof(s));
t[tmpz]=s[z];//表示一次移动,把这个状态添加到状态数组中去
t[z]=s[tmpz];
p[rear].dis=p[fron].dis+1;
strcpy(p[rear].road,p[fron].road);
strcat(p[rear].road,ch[i]);
if(notsame(rear)) rear++;//若要入队的状态没有被访问过,则成功入队
}
}
fron++;//出队
}
return fron-1;
}
int main()
{
int n,i;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
int j;
for(j=0;j<9;j++)
scanf("%d",&sta[1][j]);
int ans=bfs();
printf("Puzzle #%d\n",i);
for(int t=0;t<9;t++)
{
printf("%d ",sta[ans][t]);
if((t+1)%3==0) printf("\n");
}
printf("%s\n\n",p[ans].road);
}
return 0;
}