【题面】
题目描述:
输入输出格式:
输入格式:
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。
输出格式:
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
输入输出样例:
Input:
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Output:
7
-1
说明:
【题解】:
P.S.:这题并不是此时完成的,但思路仍是可贵的,记录下来,何乐而不为?
首先确定——DFS深搜。
然而,我们很快就发现了:DFS没有明显的深度!!!,这样的解答树是极大的(将近于枚举棋盘的全排列)。
这时,我们将不得不转变思路:IDDFS迭代加深。
注:下面代码中的DFS(sx,sy,0)
是bool
类型的。
熟练敲框架(框架!??):
for(maxstep=0;!DFS(sx,sy,0)&&maxstep<15;maxstep++);
bool DFS(int x,int y,int step)
{
if(is_finished())
{
is_solved=1;
return 1;
}
if(step>=maxstep)return 0;
for(register int i=1;i<=8;i++)
{
if(x+dx[i]>5||x+dx[i]<1||y+dy[i]>5||y+dy[i]<1)continue;
x+=dx[i],y+=dy[i];
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
if(DFS(x,y,step+1))
{
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
return 1;
}
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
x-=dx[i],y-=dy[i];
}
return 0;
}
好吧也不算太难。。。
HOWEVER——
过不了。泼冷水(谁裸迭代加深过了我给他\(10^{10^{10}}\%1RMB\))
优化??
LevelUp!——\(IDA*\)
也就是\(A*\)优化的迭代加深。
简单的来说就是:如果当前步数+理想状态(calc估价函数)都无法在maxstep步内到达目标,即剪枝。
那么估价函数怎么设定?
别急,一个一个来。
在目标棋盘上,如果一个骑士不在自己的位置上(即黑白不对应),那么这一步是一定要走的。
那么,calc()
的设定方式是显而易见了:
inline int calc()
{
register int i,j,count=0;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
if(now[i][j]!=goal[i][j]&&now[i][j]!='*'&&goal[i][j]!='*')count++;
return count;
}
好了,放CODE:
#include<iostream>
using namespace std;
const int dx[9]={0,-2,-1,1,2,2,1,-1,-2};
const int dy[9]={0,1,2,2,1,-1,-2,-2,-1};
const char goal[6][6]={{0},{0,'1','1','1','1','1'},{0,'0','1','1','1','1'},{0,'0','0','*','1','1'},{0,'0','0','0','0','1'},{0,'0','0','0','0','0'}};
char now[6][6];
bool is_solved;
int maxstep;
inline bool is_finished()
{
register int i,j;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
if(goal[i][j]!=now[i][j])return 0;
return 1;
}
inline int calc()
{
register int i,j,count=0;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
if(now[i][j]!=goal[i][j]&&now[i][j]!='*'&&goal[i][j]!='*')count++;
return count;
}
bool DFS(int x,int y,int step)
{
if(is_finished())
{
is_solved=1;
return 1;
}
if(step>=maxstep||step+calc()>maxstep)return 0;
for(register int i=1;i<=8;i++)
{
if(x+dx[i]>5||x+dx[i]<1||y+dy[i]>5||y+dy[i]<1)continue;
x+=dx[i],y+=dy[i];
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
if(DFS(x,y,step+1))
{
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
return 1;
}
swap(now[x][y],now[x-dx[i]][y-dy[i]]);
x-=dx[i],y-=dy[i];
}
return 0;
}
signed main()
{
int T;cin>>T;
while(T--)
{
is_solved=0;
register int i,j;
int sx,sy;
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
{
cin>>now[i][j];
if(now[i][j]=='*')sx=i,sy=j;
}
for(maxstep=0;!DFS(sx,sy,0)&&maxstep<15;maxstep++);
if(!is_solved)cout<<"-1"<<endl;
else cout<<maxstep<<endl;
}
return 0;
}