【题解】洪水 (2019.08.10纪中【NOIP提高组】模拟 B 组T1)BFS

题目来源:中山纪念中学

题目描述:

一天, 一个画家在森林里写生,突然爆发了山洪,他需要尽快返回住所中,那里是安
全的。
森林的地图由R行C列组成,空白区域用点“.”表示,洪水的区域用“*” 表示,而
岩石用“X”表示,另画家的住所用“D”表示,画家用“S”表示。
有以下几点需要说明:
1、 每一分钟画家能向四个方向移动一格(上、下、左、右)
2、 每一分钟洪水能蔓延到四个方向的相邻格子(空白区域)
3、 洪水和画家都不能通过岩石区域
4、 画家不能通过洪水区域(同时也不行,即画家不能移到某个格子,该格子在画家达到的同时被洪水蔓延到了,这也是不允许的)
5、 洪水蔓不到画家的住所。
给你森林的地图,编写程序输出最少需要花费多长时间才能从开始的位置赶回家中。

输入:

输入第一行包含两个整数R和C(R,C<=50)。
接下来R行每行包含C个字符(“.”、“*”、“X”、“D”或“S”)。地图保证只有一个“D”和一个“S”。

输出:

输出画家最快安全到达住所所需的时间,如果画家不可能安全回家则输出“KAKTUS”。

输入样例:

输入1:
3 3
D.*

.S.

输入2:
3 3
D.*

…S

输入3:
3 6
D…*.
.X.X…
…S.

输出样例:

输出1:
3

输出2:
KAKTUS

输出3:
6

思路:BFS

1、标记每个空地最早被洪水蔓延到的时间
2、从画家出发,然后跑一遍BFS,边界、障碍物、到达格子时间大于洪水淹没格子时间的格子不能走

AC代码:

#include<bits/stdc++.h>
using namespace std;
int r,c,vis[51][51],b[51][51],anss;
int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,-1,1};
char a[51][51];
struct node{
    int x;
    int y;
    int step;
}st,ed;
queue <node> q;
bool pd_flood(node d)
{
    if (d.x<=r&&d.x>=1&&d.y<=c&&d.y>=1&&a[d.x][d.y]=='.'&&vis[d.x][d.y]==0) return true;
    return false;
}
bool pd_art(node d)
{
    if (d.x<=r&&d.x>=1&&d.y<=c&&d.y>=1&&a[d.x][d.y]=='.'&&vis[d.x][d.y]==0&&d.step<b[d.x][d.y]||a[d.x][d.y]=='D') return true;
    return false;
}
void bfs_flood()//标记每个空地最早被洪水蔓延到的时间
{
    while (!q.empty())
    {
        node flood=q.front();
        q.pop();
        vis[flood.x][flood.y]=1;//访问标记 
        b[flood.x][flood.y]=flood.step;
        for (int i=1;i<=4;i++) //可以往四个方向蔓延
        {
            node fx;
            fx.x=flood.x+dx[i];
            fx.y=flood.y+dy[i]; 
            fx.step=flood.step+1;
            if (pd_flood(fx)==true) //洪水可以蔓延到这个点
            {
                vis[fx.x][fx.y]=1;
                q.push(fx);
            } 
        } 
    }
}
int bfs_art()
{
    while (!q.empty())
    {
        node art=q.front();
        q.pop();
        if (art.x==ed.x&&art.y==ed.y) return art.step;//到家 
        vis[art.x][art.y]=1;//访问标记 
        for (int i=1;i<=4;i++) //可以往四个方向走 
        {
            node fx;
            fx.x=art.x+dx[i];
            fx.y=art.y+dy[i];   
            fx.step=art.step+1;
            if (pd_art(fx)==true) //画家可以走这个点 
            {
                vis[fx.x][fx.y]=1;
                q.push(fx);
            } 
        } 
    }
    return -1;//画家无家可归 
}
int main()
{
    scanf("%d%d",&r,&c);
    for (int i=1;i<=r;i++) 
    {
        scanf("%s",a[i]+1);
        for (int j=1;j<=c;j++)
        {
            if (a[i][j]=='S') st.x=i,st.y=j,st.step=0;//起点 
            if (a[i][j]=='D') ed.x=i,ed.y=j;//终点 
            if (a[i][j]=='*') //洪水蔓延开始点 
            {
                node flood;
                flood.x=i;
                flood.y=j;
                flood.step=0;
                q.push(flood);
            }
        } 
    }
    memset(b,0x7f,sizeof(b));//初始化每个格子被洪水覆盖的时间为无限大,以免出现没有洪水的情况 
    bfs_flood();//洪水蔓延啦 
    while (!q.empty()) q.pop();
    q.push(st);
    memset(vis,0,sizeof(vis));
    anss=bfs_art();//画家找家ing 
    if (anss==-1) cout<<"KAKTUS"<<endl;
    else cout<<anss<<endl;
    return 0;
}

虽然很长,可是思路清晰

镇楼图:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值