[SCOI2005]骑士精神(IDA*)
对于这道题,我们第一眼:\(bfs\)爆搜
第二眼:发现事情没这么简单:这是道省选题
第三眼:仔细一想,直接\(bfs\)难道不会被卡爆吗??
第四眼:发现题目中有:“如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1”
好的,\(IDA\)*:启发式迭代加深
\(IDA\)*是什么?
其实就是在\(A\)*的基础上加上迭代加深
迭代加深其实就是每次搜索的时候限制你的搜索深度,使你的搜索树的深度保持在一个较为合理的地方,使你的时间不会爆炸,这样就可以使你在全局搜索的深度很大而答案深度很小的情况下(也是使用\(IDA\)*的条件)快速得出答案
在这道题中,明显可以看出,答案深度\(<=15\),所以我们考虑使用\(IDA\)*,在每次搜索是加上限制深度条件\(maxstep\),如果当前搜索深度\(step==maxstep\),就返回答案
作为\(A\)*的精髓,估价函数\(g(x)\)当然是我们思考的主要对象
我们可以发现,这道题给出了棋盘的目标布局
我们可以每次\(dfs\)将要进入下一层时,我们都对下一层的棋盘和目标棋盘进行对比,如果差异值\(tot+step>maxstep\),那么我们就不进入下一层
详见代码
#include<bits/stdc++.h>
using namespace std;
const int nextx[8]={1,2,2,1,-1,-2,-2,-1};
const int nexty[8]={-2,-1,1,2,2,1,-1,-2};
//目标棋盘
int goal[7][7]={
{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}
};
char ch[6][6];
int num[6][6];
bool flag=0;
int diff()//差异值
{
int tot=0;
for(int i=1;i<=5;i++)
{
for(int j=1;j<=5;j++)
{
if(num[i][j]!=goal[i][j])tot++;
}
}
return tot;
}
bool check(int x,int y)
{
return x>5||x<1||y>5||y<1;
}
void dfs(int step,int x,int y,int maxstep)
{
if(flag)return ;
if(step==maxstep)
{
if(!diff())flag=1;
return ;
}
for(int i=0;i<8;i++)
{
int xx=x+nextx[i];
int yy=y+nexty[i];
if(check(xx,yy))continue;
swap(num[x][y],num[xx][yy]);
if(step+diff()<=maxstep)dfs(step+1,xx,yy,maxstep);
swap(num[x][y],num[xx][yy]);
}
}
int main()
{
int t,stx,sty;
scanf("%d",&t);
while(t--)
{
flag=0;
for(int i=1;i<=5;i++)
{
scanf("%s",ch[i]+1);
for(int j=1;j<=5;j++)
{
if(ch[i][j]=='*')num[i][j]=2,stx=i,sty=j;
else num[i][j]=ch[i][j]-'0';
}
}
for(int i=1;i<=15;i++)
{
dfs(0,stx,sty,i);
if(flag)
{
printf("%d\n",i);
break;
}
}
if(!flag)puts("-1");
}
return 0;
}
梅子满树,清酒伊人