逃出升天

题目链接:http://172.18.66.54:50015/problem.php?id=1466

题目描述

    这里是一片n*m荒芜之体,穿过一个沼泽地就必须消耗一罐氧气(沼泽不会消失,没有氧气罐就不能穿过沼泽)。
你是否能够逃出这里。
'*':  空地
'+':经过可以获得一罐氧气 (重复经过可以重复获得)
'#':沼泽地(重复经过会重复消耗)
'S':起点
'T':终点
你的背包最多带4罐氧气, 用掉可以继续获得。

输入

多样例(n, m输入为0 0结束)
第一行:n m (n, m<=100)
2-n行:输入地图。

输出

输出是否能够从起点到达终点
是:"YES"并且输出最少的步数 
否:  "NO"

样例输入

5 5
S****
+****
+****
#####
****T
1 5
+*S#T
1 3
S#T
0 0

样例输出 

YES
8
YES
6
NO

思路:Bfs跑一下就可以了。用dis[i][j][k]记录在位置(i, j)有k罐氧气的最少步数。如果下个状态(i, j, k)的步数< dis[i][j][k]就加入队列
#include<bits/stdc++.h>
using namespace std;
const int  N=105;
const int M=0x3f3f3f3f;
int dp[N][N][8];
char mp[N][N];
int d[2][4]= {0,1,0,-1,1,0,-1,0};
struct node
{
  int x,y,n;//位置 x y 氧气瓶数 n
};
int main()
{
  int i,j,n,m,t;
  int sx,sy,ex,ey;//起点 终点
  while(scanf("%d %d",&n,&m), n*m)
  {
    for(int i=1; i<=n; i++)
    {
      scanf("%s",mp[i]+1);
      for(int j=1; j<=m; j++)
      {
        if(mp[i][j]=='S') sx=i,sy=j;
        else if(mp[i][j]=='T') ex=i,ey=j;
        for(int k=0; k<=5; k++) dp[i][j][k]=M;//初始化
      }
    }
    queue<node>q;
    dp[sx][sy][0]=0;
    q.push(node{sx,sy,0});
    while(!q.empty())//BFS
    {
      node t=q.front();
      q.pop();

      for(int i=0; i<4; i++)//四个方向
      {
        int x=t.x+d[1][i];
        int y=t.y+d[0][i];
        int c=t.n;
        if(x>n||y>m||x<1||y<1) continue;//出界
        switch(mp[x][y])
        {

        case 'S'://起点
        case '*'://空地
          if(dp[x][y][c]>dp[t.x][t.y][c]+1)//秒数比较
          {
            dp[x][y][c]=dp[t.x][t.y][c]+1;
            q.push(node{x,y,c});
          }
          break;
        case 'T'://终点
          if(dp[x][y][c]>dp[t.x][t.y][c]+1)//秒数比较
          {
            dp[x][y][c]=dp[t.x][t.y][c]+1;
            q.push(node{x,y,c});
          }
          break;
        case '#'://毒气
          if(c>0&&dp[x][y][c-1]>dp[t.x][t.y][c]+1)//氧气瓶数>0 氧气瓶-1
          {
            dp[x][y][c-1]=dp[t.x][t.y][c]+1;
            q.push(node{x,y,c-1});
          }
          break;
        case '+'://氧气
          if(c<5&&dp[x][y][c+1]>dp[t.x][t.y][c]+1)//氧气瓶+1 秒数+1
          {
            dp[x][y][c+1]=dp[t.x][t.y][c]+1;
            q.push(node{x,y,c+1});
          }
          else if(c==4&&dp[x][y][c]>dp[t.x][t.y][c]+1)//不拿氧气瓶 比较秒数
          {
            dp[x][y][c]=dp[t.x][t.y][c]+1;
            q.push(node{x,y,c});
          }
          break;
        default://其他
          break ;

        }
      }
    }
    int ans=M;
    for(int k=0; k<=4; k++)//寻找终点最小值
      ans=min(ans,dp[ex][ey][k]);

    if(ans>=M)
    {
        printf("NO\n");
    }
    else
    {
        printf("YES\n");
        printf("%d\n",ans);
    }
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值