[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
",i);
				break;
			}
		}
		if(!flag)puts("-1");
	}	
	return 0;
}
原文地址:https://www.cnblogs.com/ShuraEye/p/12110852.html