[SCOI2005]骑士精神(IDA*)

题面:[SCOI2005]骑士精神

对于这道题,我们第一眼:\(bfs\)爆搜

第二眼:发现事情没这么简单:这是道省选题

第三眼:仔细一想,直接\(bfs\)难道不会被卡爆吗??

第四眼:发现题目中有:“如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1

好的,\(IDA\)*:启发式迭代加深

\(IDA\)*是什么?

其实就是在\(A\)*的基础上加上迭代加深

还不知道\(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;
}
posted @ 2019-12-28 10:03  ShuraEye  阅读(219)  评论(0编辑  收藏  举报