Description
在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。
Input
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。
Output
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
Sample Input
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Sample Output
7
-1
一眼搜索无疑,考虑到爆搜一定会超时,而题中说在15步以内,我们可以直接枚举步数搜空点(*),然后每次判断剩下的能不能到达最终状态:如果目前状态与最终状态的不一样的点的个数加上已走的步数大于要搜的步数,就不能到达。
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int bbbb,map[6][6]={{0,0,0,0,0,0},{0,1,1,1,1,1},{0,0,1,1,1,1},{0,0,0,2,1,1},{0,0,0,0,0,1},{0,0,0,0,0,0}};
int now[6][6];
int xx[8]={-2,-1,1,2,2,1,-1,-2},yy[8]={-1,-2,-2,-1,1,2,2,1};
bool judge(int k,int maxn)
{
int cnt=0;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
if(now[i][j]!=map[i][j])
cnt++;
if(cnt+k>maxn)return false;
return true;
}
void dfs(int step,int maxn,int x,int y)
{
if(step==maxn&&!memcmp(now,map,sizeof(now)))
{
bbbb=1;return ;
}
for(int i=0;i<8;i++)
{
if(bbbb||step>=maxn)return ;
int tmpx=x+xx[i],tmpy=y+yy[i];
if(tmpx>=1&&tmpx<=5&&tmpy>=1&&tmpy<=5)
{
swap(now[x][y],now[tmpx][tmpy]);
if(judge(step,maxn))
dfs(step+1,maxn,tmpx,tmpy);
swap(now[x][y],now[tmpx][tmpy]);
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int stx,sty;
for(int i=1;i<=5;i++)
{
getchar();
for(int j=1;j<=5;j++)
{
char c;
scanf("%c",&c);
if(c=='1')now[i][j]=1;
else if(c=='0')now[i][j]=0;
else
{
now[i][j]=2;
stx=i;sty=j;
}
}
}
for(int i=0;i<=15;i++)
{
dfs(0,i,stx,sty);
if(bbbb)
{
printf("%d\n",i);
break;
}
}
if(!bbbb)
printf("-1\n");
bbbb=0;
}
}