Description
在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。
Input
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。
Output
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
启发式搜索
当前状态与目标状态相差n格则说明n-2步内不可能到达目标状态,
限制深度dfs,若经判断在限制步数内不能达到目标状态则剪枝,
逐步提高深度限制直至找到答案或深度到达15仍无解
#include<cstdio> int n; int ans[5][5]={ {1,1,1,1,1}, {0,1,1,1,1}, {0,0,2,1,1}, {0,0,0,0,1}, {0,0,0,0,0} }; int d,maxdep; bool fo; int now[5][5]; int x0,y0; int xs[]={1,1,-1,-1,2,2,-2,-2}; int ys[]={2,-2,2,-2,1,-1,1,-1}; char c; inline bool eq(){ for(int i=0;i<5;i++) for(int j=0;j<5;j++)if(ans[i][j]!=now[i][j])return 0; return 1; } inline void swap(int*a,int*b){ int t=*a; *a=*b; *b=t; } inline int minsteps(){ int a=-1; for(int i=0;i<5;i++) for(int j=0;j<5;j++)if(ans[i][j]!=now[i][j])a++; return a; } void dfs(int dep){ if(fo)return; if(eq()){ fo=1; d=dep; return; } for(int i=0;i<8;i++){ int x1=x0+xs[i],y1=y0+ys[i],x2=x0,y2=y0; if(x1<0||y1<0||x1>4||y1>4)continue; swap(now[x0]+y0,now[x1]+y1); if(dep+minsteps()<maxdep){ x0=x1;y0=y1; dfs(dep+1); x0=x2;y0=y2; } swap(now[x0]+y0,now[x1]+y1); } } void readc(char&c){ while(c=getchar()){ if(c=='0'||c=='1'||c=='*')return; } } int main(){ scanf("%d",&n); while(n--){ for(int i=0;i<5;i++){ for(int j=0;j<5;j++){ readc(c); now[i][j]=c=='0'?0:c=='1'?1:2; if(c=='*')x0=i,y0=j; } } d=-1; fo=0; for(maxdep=1;maxdep<=15&&!fo;maxdep++)dfs(0); printf("%d\n",d); } return 0; }