CF_329_B----AcWing_3825_逃离大森林(BFS究极模板)

3 篇文章 0 订阅
3 篇文章 0 订阅

原题链接:https://www.acwing.com/problem/content/3828/

你是一个宝可梦饲养员,你正在进行你的冒险之旅。

当前,你的目标是逃离飞鸟森林。 飞鸟森林可以表示为一个 r×c 的方格矩阵。 每个方格,要么是树木,要么是空地。 空地中可能包含 0
个或多个宝可梦饲养员(森林中可能存在除你以外的其他饲养员)。 所有饲养员(包括你在内)都不能进入到包含树木的方格之中。
有一个方格为出口方格,到达这里就可以逃离大森林。 出口方格一定是空地。
最初始的方格矩阵将提供给你,这包含了你的初始位置,出口方格的位置、空地和树木的分布以及其他所有饲养员的位置, 下图是一个初始方格矩阵的示例:
1.png
所有饲养员(包括你)都可以在森林中进行移动。 每次移动可以: 原地不动。也就是放弃本次移动。 沿上下左右四个方向移动一格距离。
注意,任何人都不可能移动至带有树木的方格中。 如果你在一次移动中,抵达了出口方格,那么下次移动你就可以选择离开森林。
其他饲养员不会以这种方式主动离开森林。 在你进行一次移动时,其他所有饲养员也会同时进行一次移动(每个饲养员的移动方式可能不尽相同)。 当你和
t 个其他饲养员位于同一方格之中时,就会和他们进行 t 场一对一的战斗(战斗时间忽略不计)。
所有跟你战斗过的饲养员都会失去所有战斗力,无法再挑战你,只能饮恨离开森林。
注意,在你离开森林的那次移动中,即使有饲养员在此次移动中抵达出口方格,你也不会和他们发生战斗。
另外,其他饲养员只会和你发生战斗,其他饲养员之间不会发生战斗(可能有多个饲养员位于同一方格中)。
既然要离开森林,你就需要在开始行动之前制定一条行进路线,确定你的一系列移动。
在确定这个具体行动计划后,你一定会严格遵循制定好的路线开展你的所有移动。 并且你还会将你的行动路线提前公开发布到博客上。
其他所有饲养员都关注了你的博客,并且迫切的渴望与你战斗。
因为已经提前知道了你的所有移动顺序,所以其他饲养员当中,有机会在你的行进过程中碰到你的,都会主动撞上你,以确保能够和你战斗,而无论如何也碰不到你的,就会原地不动,不白费力气。
你是个不喜欢战斗的人,所以你想要制定一条最为合理的行进路线,使得你在逃离大森林的过程中进行战斗的场次尽可能少。
注意,为了达到这一目的,即使行进路线长于最短行进路线也在所不惜。

输入格式

第一行包含两个整数 r 和 c。 接下来 r 行,每行包含一个长度为 c 的字符串,表示森林矩阵。每个字符可能是:

  1. T:表示树木方格。
  2. S:表示你的初始位置方格,这是一个空地,保证有且仅有一个。
  3. E:表示出口方格,这是一个空地,保证有且仅有一个。

一个数字(0∼9):表示空地方格,数字为 x 则表示该空地上有 x 个饲养员。 保证你一定可以从初始位置走到出口方格位置。

输出格式
输出一个整数,表示你最少需要进行的战斗场次。

数据范围
1≤r,c≤1000

输入样例1:
5 7
000E0T3
T0TT0T0
010T0T0
2T0T0T0
0T0S000

输出样例1:
3
样例1解释:
森林方格矩阵如下所示:

2.png
蓝色线路即为你可以选择的行进路线,在该行进路线中,只有左下方的三人可以撞到你,而右上角的三人无法撞到你,所以只需要进行三场战斗。

输入样例2:
1 4 SE23

输出样例2:
2

样例2解释:
森林方格矩阵如下所示:
3.png
你在第一次移动中,直接移动至出口方格处:
4.png
与此同时,右边的两个人也移动至出口方格处,你们发生战斗(最右边的三人因为赶不上你,所以原地不动):
5.png
你把两个挑战者干跑了:
6.png
在第二次移动中,你选择离开森林:
7.png

  • 该来的它逃不掉的QAQ!!!
  • 今天整理一道BFS究极模板题,学会即小成。
  • 解题思路:
    该题需要找考虑一条路径从你开始到出口,如果路中间遇到其他饲养员则你们之间发生争斗,
    求最少与几名饲养员发生争斗。
    当然如果找到一条路径在路中间与其他饲养员相遇,则其到出口距离必然小于你与出口的最小距离,
    所以本题转化为有几个饲养员比你先到达终点(即其与终点距离小于你与终点距离)。
    即从终点开始找每一个非树的点与终点的最小距离,
    然后找出饲养员与终点位置小于你与终点之间距离的饲养员数量加到答案里面,输出即可。

代码如下:

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;//存储一对坐标
const int N = 1010;
char g[N][N];//定义地图
int n,m;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};//定义四个方向偏移量
int dist[N][N];//存储每个点与终点之间的最短距离
int bfs()
{
    memset(dist, 0x3f, sizeof dist);//初始化距离为正无穷
    int sx,sy;//终点坐标
    for (int i = 0; i < n; i ++ )
    {
        for (int j = 0; j < m; j ++ )
        {
            if(g[i][j]=='E')
            {
                sx=i;
                sy=j;
            }
        }
    }
    queue<PII> q;
    q.push({sx,sy});//终点坐标入队
    dist[sx][sy]=0;//把出口与出口距离置为0
    while(q.size())
    {
        auto t=q.front();//取队头,
        q.pop();//删除队头
        for(int i=0;i<4;i++)//遍历与队头相邻的四个方向
        {
            int x=t.x+dx[i];
            int y=t.y+dy[i];
            if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]!='T')//判断边界与树
            {
                if(dist[x][y]>dist[t.x][t.y]+1)//如果当前位置与终点距离没有被更新则更新当前位置与终点距离
                {
                    dist[x][y]=dist[t.x][t.y]+1;//更新距离
                    q.push({x,y});//当前点入队
                }
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(g[i][j]=='S')//找出你的位置
            return dist[i][j];//你的位置与终点距离
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>g[i][j];//输入地图
        }
    }
    int t = bfs();//你与终点最短距离
    int res=0;//记录答案
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            // if(dist[i][j]!=1061109567) cout<<dist[i][j]<<" ";
            // else cout<<"T ";
            if(g[i][j]>'0'&&g[i][j]<='9'&&dist[i][j]<=t)//其他判断饲养员是否一定与你相遇
            {
                res+=g[i][j]-'0';
            }
        }
        // cout<<"\n";
    }
    cout<<res<<"\n";
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

画江湖がº

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值