http://www.lydsy.com/JudgeOnline/problem.php?id=1085
https://www.luogu.org/problem/show?pid=2324
从ZJOI2017讲课学来的新东西。。。
这题也就是启发式搜索(或者称A*)
。。哦不对,是IDA*(迭代加深启发式搜索)
我们找到空位置以后直接搜索状态直到目标状态
但是显然的,暴搜是过不掉这题的
一个最优性剪枝:计算不在目标位置的骑士个数m,如果m不足以在15步范围内把所有骑士归位,剪枝(写出这个DFS就升级成为A*了)
但是这样好像还是会T啊(不过我没试过)
题中有说,步数大于15步输出-1,所以最深层数是15
有限制层数而且那么小为什么不用迭代加深呢
于是我们就可以把上面的A*优化成IDA*
也就是限制层数
这个时候把剪枝内容改一下:计算不在目标位置的骑士个数m,如果m不足以在k步范围内把所有骑士归位,剪枝(k是限制层数)
然后就可以愉快地AC了
后注:哦对,这题数据luogu中没有答案为0的情况,其实0也可以是答案当输入状态为最终状态时
感谢lc233提醒
我一开始的程序是可以被卡掉的,改好的程序在下面
#include<bits/stdc++.h>
using namespace std;
int a[10][10];
const int dx[9]={0,1,1,-1,-1,2,2,-2,-2};
const int dy[9]={0,2,-2,2,-2,1,-1,1,-1};
bool flag;
const int b[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}};
inline bool check(int a[10][10]){//目标状态判定
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)if(a[i][j]!=b[i][j])return 0;
return 1;
}
inline bool A(int a[10][10],int p,int k){//最优性剪枝
int m=0;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)if(a[i][j]!=b[i][j]){
m++;
if(m+p>k)return 0;
}
return 1;
}
inline void dfs(int p,int a[10][10],int k,int x,int y){
if(flag)return;
if(p==k){
if(check(a))flag=1;
return;
}
for(int i=1;i<=8;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||xx>5||yy<1||yy>5)continue;
swap(a[x][y],a[xx][yy]);
if(A(a,p,k))dfs(p+1,a,k,xx,yy);
swap(a[x][y],a[xx][yy]);
}
}
int main()
{
int t,x,y;scanf("%d",&t);
while(t--){
flag=0;
for(int i=1;i<=5;i++){
char c[10];scanf("%s",c+1);
for(int j=1;j<=5;j++)
if(c[j]=='*')a[i][j]=2,x=i,y=j;
else a[i][j]=c[j]-'0';
}
for(int i=0;i<=15;i++){//i限制层数
dfs(0,a,i,x,y);
if(flag){
printf("%d\n",i);
break;
}
}
if(flag)continue;
printf("-1\n");
}
return 0;
}