• [SCOI2005]骑士精神


    题面传送门

    我们发现只有25个格子,应该是可以用爆搜过掉这道题的。但是裸的dfs时间复杂度过高,我们要进行相应的优化。

    首先,由于马的数量过多,我们应该选择让空格“走”。

    接下来我们发现这道题又很明显的一个限制条件,最多不能超过15步,所以我们可以使用迭代加深进行优化,所谓的迭代加深搜索,本质上还是dfs,但是它每次会设置一个深度上限maxdep,使得搜索树的深度不超过maxdep,这样做可以让它遍历更多的分支,更广泛的求解。

    然而,即使加上了迭代加深优化,我们依然不能通过此题,因此我们引入了第二种优化:启发式搜索,著名的A*算法就是一种启发式搜索。

    来自https://blog.csdn.net/denghecsdn/article/details/78778769的A*核心思想详解:

    “A*成功的秘决在于,它把Dijkstra算法(靠近初始点的结点)和BFS算法(靠近目标点的结点)的信息块结合起来。在讨论A*的标准术语中,g(n)表示从初始结点到任意结点n的代价,h(n)表示从结点n到目标点的启发式评估代价(heuristic estimated cost)。在上图中,yellow(h)表示远离目标的结点而teal(g)表示远离初始点的结点。当从初始点向目标点移动时,A*权衡这两者。每次进行主循环时,它检查f(n)最小的结点n,其中f(n) = g(n) + h(n)。”

    然而上述思想显然是针对BFS的,我们可以结合迭代加深将其“改造”成我们需要的dfs算法,这种算法就叫做启发式迭代加深搜索(IDA*)

    那么回到这个题目本身,我们如何设计这个估价函数呢?我们发现,在最乐观的情况下,每次交换时,都把相应棋子交换到标准位置,因此我们只要统计最终状态和当前状态不一样的数量即可。

    然后使用IDA*搜索即可。

    参考代码:

     1 #pragma GCC optimize(3,"Ofast","inline") 
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #define int long long
     6 using namespace std;
     7 int read()
     8 {
     9     int x=0,f=1;char ch=getchar();
    10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    11     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    12     return x*f;
    13 }
    14 int n;
    15 int _std[10][10]=
    16 {
    17     {0,0,0,0,0,0},
    18     {0,1,1,1,1,1},
    19     {0,0,1,1,1,1},
    20     {0,0,0,2,1,1},
    21     {0,0,0,0,0,1},
    22     {0,0,0,0,0,0}
    23 };
    24 int dx[8]={-1,1,2,2,1,-1,-2,-2};
    25 int dy[8]={-2,-2,-1,1,2,2,1,-1};
    26 int a[10][10],T,suc,sx,sy;
    27 char ch;
    28 int evaluate()
    29 {
    30     int cnt=0;
    31     for(int i=1;i<=5;i++)
    32     {
    33         for(int j=1;j<=5;j++)
    34         {
    35             if(a[i][j]!=_std[i][j])++cnt;
    36         }
    37     }
    38     return cnt;
    39 }
    40 void A_star(int step,int x,int y,int maxdep)
    41 {
    42     if(step==maxdep)
    43     {
    44         if(!evaluate())suc=step;
    45         return;
    46     }
    47     for(int i=0;i<=7;i++)
    48     {
    49         int xx=x+dx[i],yy=y+dy[i];
    50         if(xx<1||xx>5||yy<1||yy>5)continue;
    51         swap(a[xx][yy],a[x][y]);
    52         if(step+evaluate()<=maxdep)A_star(step+1,xx,yy,maxdep);
    53         swap(a[xx][yy],a[x][y]);
    54     }
    55 }
    56 signed main()
    57 {
    58     freopen("knight.in","r",stdin);
    59     freopen("knight.out","w",stdout);
    60     ios::sync_with_stdio(0);
    61     cin>>T;
    62     while(T--)
    63     {
    64         suc=0;
    65         for(int i=1;i<=5;i++)
    66         {
    67             for(int j=1;j<=5;j++)
    68             {
    69                 cin>>ch;
    70                 if(ch=='*')a[i][j]=2,sx=i,sy=j;
    71                 else a[i][j]=ch-'0';
    72             }
    73         }
    74         if(!evaluate())
    75         {
    76             cout<<0<<"
    ";
    77             continue;
    78         }
    79         for(int i=1;i<=15;i++)
    80         {
    81             A_star(0,sx,sy,i);
    82             if(suc)break;
    83         }
    84         if(suc)cout<<suc<<endl;
    85         else cout<<-1<<endl;
    86     }
    87     return 0;
    88 }
    [SCOI2005]骑士精神

      

  • 相关阅读:
    docker中centos7安装ssh服务
    redis加入systemctl服务
    elasticsearch设置执行脚本并添加开机启动 (转)
    CentOS7使用firewalld打开关闭防火墙与端口
    腾讯地图JSAPI开发demo 定位,查询
    C# 开发AliYun(阿里云) 小蜜调用接口代码
    VSCode 开发Core教程
    Rabbit原理理解
    Exceptionless 本地部署
    Visual Studio 2019 自带混淆工具DotFuscator不需要去网络下载
  • 原文地址:https://www.cnblogs.com/szmssf/p/11730094.html
Copyright © 2020-2023  润新知