ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[SCOI2005]骑士精神

2019-05-16 20:44:41  阅读:311  来源: 互联网

标签:剪枝 精神 int 搜索 ans SCOI2005 骑士 maxn


题目描述

在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。

img

输入格式

第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。

输出格式

对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。


不难想到搜索可以做这题。由于骑士只能往空格走,与其枚举每个骑士可以走的方向不如直接搜索空格往哪走。我们尝试用深搜做这题。

很容易想出状态:当前的棋盘,空格的位置,走的步数。棋盘可以开个全局变量来存。每次空格可以往8个方向走,只需往8个方向分别拓展即可。

考虑剪枝:

1.上下界剪枝:

上界:题目给的是15次。

下界:最好的情况莫过于跳

\[ \sum_{i=1}^{n}\sum_{j=1}^{n}[g[i][j]≠des[i][j]] \]

次了。虽然这对剪枝没什么用

2.搜索顺序:由于每个格子可以重复走,所以顺序随意。

3.排除等效冗余:往前走了之后又往回走是没有意义的,所以我们应该避免走上一次走的方向的反方向。

4.最优化剪枝:如果当前搜到的答案为ans,那么当步数≥ans时就没必要往下搜了,回溯。

5.记忆化:没什么好记的,而且记了容易MLE。跳过。

有了这么多剪枝,你的搜索已经很快了,但仍然不尽人意。由于本题的答案很小,我们考虑进一步优化。

把DFS加上迭代加深。从1开始枚举搜索深度,当搜索到答案时必定是最优解,所以最优化剪枝就没必要做了。如果搜到了上界15,那么就是无解。于是我们的上下界剪枝也没有必要做了。

然而IDFS仍然不够快,因为这题的答案也并不像某些ans≤5那么小,当我们的深度枚举到ans时,我们面对的搜索树其实是非常大的,然而剪枝已经减不掉了。

根据IDFS的性质,像广搜一样,当第一次搜到答案时就是最优解,直接回溯。那我们管它多大的搜索树,我们只让程序快点搜出答案,即优先往答案所在的方向走即可。这就要用到启发式搜索IDA * 了。

设计估价函数。由于估价函数必须小于等于实际值,我们可以结合之前的下界来设计。也就是说,估价函数就是当前状态与目标状态不同的格子数:

\[ f(g[][])=\sum_{i=1}^{5}\sum_{j=1}^{5}[g[i][j]≠des[i][j]] \]

当当前深度加上预估值大于了搜索深度时就可以不往下搜了。

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 6
using namespace std;

const int dir[8][2]={{1,2},{2,1},{2,-1},{1,-2},{-1,2},{-2,1},{-2,-1},{-1,-2}};
const int des[maxn][maxn]={{},{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}};
int g[maxn][maxn],ans;

inline int evaluate(){
    int cnt=0;
    for(register int i=1;i<=5;i++) for(register int j=1;j<=5;j++) if(g[i][j]!=des[i][j]) cnt++;
    return cnt;
}
inline bool check(const int &x,const int &y){ return x<1||5<x||y<1||5<y; }
void IDAstar(int x,int y,int dep,int pre_dir,const int &lim){
    if(dep==lim){ if(!evaluate()) ans=true; return; }
    for(register int i=0;i<8;i++) if(i+pre_dir!=7){
        int tx=x+dir[i][0],ty=y+dir[i][1];
        if(!check(tx,ty)){
            swap(g[x][y],g[tx][ty]);
            if(evaluate()+dep<=lim) IDAstar(tx,ty,dep+1,i,lim);
            swap(g[x][y],g[tx][ty]);
            if(ans) return;
        }
    }
}

int main(){
    int t,sx,sy; scanf("%d",&t);
    while(t--){
        for(register int i=1;i<=5;i++){
            for(register int j=1;j<=5;j++){
                char in; cin>>in;
                if(in=='*') g[i][j]=2,sx=i,sy=j;
                else g[i][j]=in-'0';
            }
        }

        if(!evaluate()){ puts("0"); continue; }
        ans=false;
        for(register int maxdep=1;maxdep<=15;maxdep++){
            IDAstar(sx,sy,0,-1,maxdep);
            if(ans){ printf("%d\n",maxdep); goto Lzs; }
        }
        puts("-1");
        Lzs:;
    }
    return 0;
}

标签:剪枝,精神,int,搜索,ans,SCOI2005,骑士,maxn
来源: https://www.cnblogs.com/akura/p/10877789.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有