Luogu-P2324-[SCOI2005]骑士精神

【题面】

题目描述:

Luogu-P2324-[SCOI2005]骑士精神

输入输出格式:

输入格式:

第一行有一个正整数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

说明:

Luogu-P2324-[SCOI2005]骑士精神

【题解】:

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;
}
上一篇:1257:Knight Moves


下一篇:780. Reaching Points