题意:
给定一个5x5的棋盘及24个黑白棋子和一个空格,问你最少经过多少步的移动后可以到达目标状态。
思路:
这个题目的思路和八数码问题是一样的,但因为有25个格子,所以不能用康托展开进行判重,我选用了字符串BKDRHash进行的判重。
但是如果我将这个棋盘展开成一维数组做的时候总是答案错误,当用二维数组表示的时候就可以,现在我还是不知道原因。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define Mod 499979
#define MaxSize 500000
typedef char State[5][5];
State st[MaxSize],vis[MaxSize],goal={{'1','1','1','1','1'},
{'0','1','1','1','1'},
{'0','0',' ','1','1'},
{'0','0','0','0','1'},
{'0','0','0','0','0'}};
int step[MaxSize],a[MaxSize];
int dx[]={-2,-2,-1,1,2,2,1,-1};
int dy[]={-1,1,2,2,1,-1,-2,-2};
int BKDRHash(State& s)
{
int i,j;
int seed=31;
int sum=0;
for(i=0;i<5;i++)
for(j=0;j<5;j++)
sum=sum*seed+s[i][j];
sum=sum&0x7fffffff;
return sum%Mod;
}
int Insert(int s)
{
int i,j,k;
int h=BKDRHash(st[s]);
if(a[h]==0)
{
a[h]=1;
memcpy(vis[h],st[s],sizeof(st[s]));
return 1;
}
while(a[h]!=0)
{
if(memcmp(vis[h],st[s],sizeof(st[s]))==0)
return 0;
h++;
}
a[h]=1;
memcpy(vis[h],st[s],sizeof(st[s]));
return 1;
}
int bfs()
{
memset(a,0,sizeof(a));
Insert(0);
int front=0, rear=1,i,j;
step[front]=0;
while(front<rear)
{
State& s=st[front];
if(step[front]>10)
return -1;
if(memcmp(goal,s,sizeof(s))==0)
return step[front];
int x,y;
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
if(s[i][j]==' ')
break;
}
if(j<5)
break;
}
x=i,y=j;
for(i=0;i<8;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=0&&xx<5&&yy>=0&&yy<5)
{
State& t=st[rear];
memcpy(t,s,sizeof(s));
t[x][y]=s[xx][yy];
t[xx][yy]=s[x][y];
step[rear]=step[front]+1;
if(Insert(rear))
rear++;
}
}
front++;
}
return -1;
}
int main()
{
int i,j,k=0,t,m;
char s[10][10];
scanf("%d",&t);
getchar();
while(t--)
{
for(i=0;i<5;i++)
gets(s[i]);
for(i=0;i<5;i++)
for(j=0;j<5;j++)
st[0][i][j]=s[i][j];
int ans=bfs();
if(ans!=-1)
printf("Solvable in %d move(s).",ans);
else
printf("Unsolvable in less than 11 move(s).");
printf("\n");
}
return 0;
}