【XSY2498】贪吃蛇(bfs/dfs)

4 篇文章 0 订阅

题面

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

在这里插入图片描述

题解

d f s dfs dfs玄学复杂度过去了……

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

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

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

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

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

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

因为当前时间为 t t t秒,贪吃蛇走到下一个格子需要 1 1 1秒,然后等贪吃蛇完全经过需要 k k k秒,所以 t i m e [ x i ] [ y i ] = t + 1 + k time[xi][yi]=t+1+k time[xi][yi]=t+1+k秒,那么我们就能在 O ( 1 ) O(1) 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;
}

总结

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值