首页 > 其他分享 >【XSY2498】贪吃蛇(bfs_dfs)

【XSY2498】贪吃蛇(bfs_dfs)

时间:2022-10-30 10:26:12浏览次数:41  
标签:yi xi 格子 int XSY2498 dfs bfs 贪吃蛇

题面

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input & Sample Output

【样例输入1】

4 5
##...
..1#@
432#.
...#. 

【样例输出1】

4 

【样例输入2】

4 4
#78#
.612
.543
..@. 

【样例输出2】

6 

【样例输入3】

3 2
3@
2#
1# 

【样例输出3】

-1

HINT

在这里插入图片描述

题解

\(dfs\)玄学复杂度过去了……

注:这题用\(bfs\)的时间复杂度更低,为\(O(nm4^k)\)。我只是考场上用了\(dfs\)加小小的优化卡过去了。这篇题解只是讲用\(dfs\)怎么做一个小优化,不想看的可以跳过。

这个优化就是在处理如何维护贪吃蛇的位置(因为要防止贪吃蛇吃到自己)的问题上,如果每走一步都\(O(k)\)更新一遍会比较慢(虽然在\(k<=9\)的情况下也慢不了多少),所以我们打算每次通过\(O(1)\)来操作

我们考虑为整个过程建一个时间,即贪吃蛇每走一格就时间\(+1\)秒,那么我们考虑定义一个数组\(time[i][j]\),表示格子\([i,j]\)什么时候是空的。

我们不妨将贪吃蛇看成很多段,每段是一格长,那么贪吃蛇的头就是第一段,尾就是最后一段。

那么当游戏开始时,贪吃蛇的最后一段(尾部)的格子肯定至少在\(1\)秒后才是空的,贪吃蛇的倒数第二段的格子肯定至少在\(2\)秒后才是空的(第\(1\)秒后,倒数第一段走到第\(1\)秒前倒数第二段的格子,第\(2\)秒后,倒数第一段离开)……贪吃蛇的第\(i\)段的格子肯定至少在\(k-i+1\)秒后才是空的……贪吃蛇的第\(1\)段的格子肯定至少在\(k\)秒后才是空的。(\(k\)的解释见题面)

对于每当贪吃蛇走一步维护\(time\)的问题,我们发现只有贪吃蛇的头走到的格子的\(time\)才会有变化,那么我们考虑,假设当前时间为\(t\)秒,贪吃蛇的头下一步要走到\([xi,yi]\)。

因为当前时间为\(t\)秒,贪吃蛇走到下一个格子需要\(1\)秒,然后等贪吃蛇完全经过需要\(k\)秒,所以\(time[xi][yi]=t+1+k\)秒,那么我们就能在\(O(1)\)的时间内维护贪吃蛇位置的变化了。

最后完整代码加注释如下:

#include<bits/stdc++.h>
 
#define N 20
#define K 15
#define INF 0x7fffffff
 
using namespace std;
 
struct data
{
    int x,y,s;
};
 
int n,k,m,edx,edy,ans=INF,tim[N][N],snax[N],snay[N];
//edx、edy为终点的坐标
//snax[]、snay[]为贪吃蛇的每一段的坐标
int fx[]={-1,0,1,0},fy[]={0,1,0,-1};
char ch[N][N];
bool vis[N][N];//是否走过
 
bool check(int x,int y)
{
    return x<1||x>n||y<1||y>m;
}
 
void dfs(int x,int y,int s,int t)
{
    if(x==edx&&y==edy)
    {
        ans=min(ans,s);
        return;
    }
    if(s>=ans)return;
    for(int i=0;i<4;i++)
    {
        int xi=x+fx[i],yi=y+fy[i];
        if(vis[xi][yi]||check(xi,yi)||ch[xi][yi]=='#'||tim[xi][yi]-t>1)continue;
        int tt=tim[xi][yi];
        tim[xi][yi]=t+k+1;//time值更新
        vis[xi][yi]=true;//记录贪吃蛇来过这个位置,防止死循环
        dfs(xi,yi,s+1,t+1);
        vis[xi][yi]=false;//记得改回来哦
        tim[xi][yi]=tt;
    }
}
 
void bfs()
{
    queue<data>q;
    q.push((data){snax[1],snay[1],0});
    while(!q.empty()&&(q.front().x!=edx||q.front().y!=edy))
    {
        data now=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int xi=now.x+fx[i],yi=now.y+fy[i];
            if(vis[xi][yi]||check(xi,yi)||ch[xi][yi]=='#')continue; 
            vis[xi][yi]=true;
            q.push((data){xi,yi,now.s+1});
        }
    }
    if(q.empty())puts("-1");
    else printf("%d\n",q.front().s);
}
 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",ch[i]+1);
        for(int j=1;j<=m;j++)
        {
            if(ch[i][j]=='@')
            {
                edx=i,edy=j;
            }
             
            if('1'<=ch[i][j]&&ch[i][j]<='9')
            {
                snax[ch[i][j]-'0']=i,snay[ch[i][j]-'0']=j;
                k=max(k,ch[i][j]-'0');
            }
        }
    }
    bool flag=true;
    for(int i=0;i<4;i++)//特判终点的四周被堵住了
    {
        int xi=edx+fx[i];
        int yi=edy+fy[i];
        if(!check(xi,yi)&&ch[xi][yi]!='#')
        {
            flag=false;
            break;
        }
    }
    if(flag)
    {
        puts("-1");
        return 0;
    }
    if(k==1)//特判k=1用bfs更快
    {
        bfs();
        return 0;
    }
    for(int i=1;i<=k;i++)
        tim[snax[i]][snay[i]]=k-i+1;//第0秒时的time
    dfs(snax[1],snay[1],0,0);
    if(ans!=INF)printf("%d\n",ans);
    else puts("-1");
    return 0;
}

总结

用时间复杂度高的算法时,要么想另一种做法,要么手造大数据测试并丧心病狂地卡常。

标签:yi,xi,格子,int,XSY2498,dfs,bfs,贪吃蛇
From: https://www.cnblogs.com/ez-lcw/p/16840598.html

相关文章

  • Acwing 4708 . 立方体(三维bfs)
    https://www.acwing.com/problem/content/4711/题目没什么难度,但是就是三维有些东西不经常定义记不住。写个题解记录一下吧Acwing1096.地牢大师https://www.acwing.co......
  • spfa和bfs的区别
    \(spfa\)和\(bfs\)的区别\(spfa\)在形式上和\(bfs\)非常类似,不同的是\(bfs\)中一个点出了队列就不可能重新进入队列,但是\(spfa\)中一个点可能在出队列之后再次被放入队列,......
  • BFS最短路径(求x到y的最少计算次数)
     给定两个-100到100的整数x和y,对x只能进行加1,减1,乘2操作,问最少对x进行几次操作能得到y?例如:a=3,b=11:可以通过3*2*2-1,3次操作得到11;a=5,b=8:可以通过(5-1)*2,2次操作得到......
  • BFS--宽搜求最短路径
    1010#S######.#......#..#.#.##.##.#.#........##.##.####....#....#.#######.#....#......####.###.....#...G##是障碍,.是通道,S是起点,G是终点求出最短路径长度......
  • P7078 [CSP-S2020] 贪吃蛇
    [CSP-S2020]贪吃蛇LuoguP7078题目描述草原上有\(n\)条蛇,编号分别为\(1,2,\ldots,n\)。初始时每条蛇有一个体力值\(a_i\),我们称编号为\(x\)的蛇实力比编号为......
  • POJ 3278(BFS-搜索范围)
    这题是BFS水的主要是范围0<=n,k<=100000 但是有可能搜到200000……半天功夫才A.programP3278;constmaxn=200000;varn,k,i,j:longint;q,deep:array[1..maxn]of......
  • 水灾 (BFS-先洪水后寻路)
    水灾(sliker)大雨应经下了几天雨,却还是没有停的样子。ksy刚从外地回来,知道不久除了自己家,其他的地方都将会被洪水淹没。ksy的老家可以用一个N*M的地图表示,地图上有五种符号:“.......
  • Nearest Excluded Points ( 转化思想 +多源BFS )
     思路:思路暴力枚举每一个点,暴力做时间会超观察发现:每一个所找的空白点,一定是紧紧挨着红色的点, 于是把这些空白点入队,然后利用bfs,即可搞出来空间用ma......
  • 三维空间的dfs和bfs
    三维空间的dfs和bfs去枚举每一步的6个方向的时候都会用到三个偏移量数组dx[]={1,0,0,-1,0,0};dy[]={0,1,0,0,-1,0};dz[]={0,0,1,0,0,-1};//这样一个for就可以枚举出......
  • 初学bfs
    dfs利用的是栈,bfs利用的是队列如同y总所说的,不需要理解如何用队列实现一个bfs而是跟着y总,告诉我们怎么做,然后我们自己判断一下这种是不是bfs如图:取出的顺序和加入的......