bzoj1085 [SCOI2005]骑士精神
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1085
题意:
在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。
如果能在15步内完成,输出步数,否则输出-1。
数据范围
数据组数 T<=10
题解:
要求15步内完成,但是广搜状态很多,于是考虑迭代加深搜索。
A*估价函数剪枝,既要要力度合理,且不要把正解减去了,
那么既然有了IDA的当前深度的限制,就把“当前最少要走的都超了”的减去。
最少要走的步数即是和最终图不一样的数量-1。
这个估价函数可以在交换两个格子时顺便维护。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int T,n=5;
int a[10][10],s[10][10];
int fx[8]={1,1,-1,-1,2,2,-2,-2},fy[8]={2,-2,2,-2,1,-1,1,-1};
char ss[10][10];
bool check()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]!=s[i][j]) return 0;
return 1;
}
bool dfs(int now,int x,int y,int enval,int dep)
{
if(now==dep) return check();
for(int i=0;i<8;i++)
{
int X=x+fx[i]; int Y=y+fy[i];
if(X<=0||X>5||Y<=0||Y>5) continue;
int pre=(a[x][y]!=s[x][y])+(a[X][Y]!=s[X][Y]);
swap(a[x][y],a[X][Y]);
int nn=(a[x][y]!=s[x][y])+(a[X][Y]!=s[X][Y]);
int nenv=enval-pre+nn;
if(nenv+now<=dep)
if(dfs(now+1,X,Y,nenv,dep)) return 1;
swap(a[x][y],a[X][Y]);
}
return 0;
}
int main()
{
scanf("%d",&T);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if((i<=2&&j>=i)||(j>i)) s[i][j]=1;
else if(i==j&&i==3) s[i][j]=-1;
else s[i][j]=0;
}
while(T--)
{
for(int i=1;i<=n;i++)
scanf("%s",ss[i]+1);
int cnt=0;
int sx,sy;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(ss[i][j]=='1') a[i][j]=1;
else if(ss[i][j]=='*') {a[i][j]=-1;sx=i;sy=j;}
else a[i][j]=0;
if(a[i][j]!=s[i][j]) cnt++;
}
if(cnt==0) {printf("0\n"); continue;}
cnt--;
bool flag=0;
for(int dep=1;dep<=15;dep++)
{
if(dfs(0,sx,sy,cnt,dep))
{printf("%d\n",dep); flag=1; break;}
}
if(!flag) printf("-1\n");
}
return 0;
}