[BFS]洪水

题目描述

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

Input

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

Output

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

Sample Input

输入1:
3 3
D.*

.S.

输入2:
3 3
D.*

..S

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

分析

这题其实很简单,洪水单独一个队列bfs,画家一个队列bfs,然后判断画家到某格时深度是否比洪水深,深就不能过了,然后每个点只用走一次,因为宽度优先搜索先搜到的深度一定最小

#include <iostream>
#include <cstdio>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int r,c,k;
int b[51][51];
int sx,sy,ex,ey;
int q[2501][2];
int dep[51][51][2];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
bool judg(int x,int y)
{
    return x>=1&&x<=r&&y>=1&&y<=c&&b[x][y]==0;
}
bool judge(int x,int y,int z)
{
    return x>=1&&x<=r&&y>=1&&y<=c&&b[x][y]<=0&&z<dep[x][y][0];
}
void bfs1()
{
    int h=0,i,j;
    bool w[51][51];
    rep(i,1,50) rep(j,1,50) w[i][j]=0;
    do
    {
        h++;
        rep(i,0,3)
        if (judg(q[h][0]+dx[i],q[h][1]+dy[i])&&!w[q[h][0]+dx[i]][q[h][1]+dy[i]])
        {
            k++;
            q[k][0]=q[h][0]+dx[i];
            q[k][1]=q[h][1]+dy[i];
            w[q[k][0]][q[k][1]]=1;
            dep[q[k][0]][q[k][1]][0]=dep[q[h][0]][q[h][1]][0]+1;
        }
    }
    while (h<k);
}
void bfs2()
{
    int h=0,t=1,i,j,state[2501][2];
    bool w[51][51];
    rep(i,1,50) rep(j,1,50) w[i][j]=0;
    state[1][0]=sx;state[1][1]=sy;w[sx][sy]=1;
    do
    {
        h++;
        rep(i,0,3)
        if (judge(state[h][0]+dx[i],state[h][1]+dy[i],dep[state[h][0]][state[h][1]][1]+1)&&!w[state[h][0]+dx[i]][state[h][1]+dy[i]])
        {
            t++;
            state[t][0]=state[h][0]+dx[i];
            state[t][1]=state[h][1]+dy[i];
            w[state[t][0]][state[t][1]]=1;
            dep[state[t][0]][state[t][1]][1]=dep[state[h][0]][state[h][1]][1]+1;
        }
    }
    while (h<t);
}
void init()
{
    int i,j;
    char p;
    scanf("%d%d",&r,&c);
    rep(i,1,r)
    rep(j,1,c)
    dep[i][j][0]=2147483647;
    rep(i,1,r)
    rep(j,1,c)
    {
        do
        {
            scanf("%c",&p);
        }
        while (p!='*'&&p!='.'&&p!='X'&&p!='S'&&p!='D');
        switch (p)
        {
            case 'S':{
                sx=i;sy=j;
                break;
            }
            case 'X':{
                b[i][j]=1;
                break;
            }
            case '*':
            {
                k++;
                q[k][0]=i;q[k][1]=j;
                dep[i][j][0]=0;
                b[i][j]=2;
                break;
            }
            case 'D':{
                ex=i;ey=j;
                b[i][j]=-1;
                break;
            }
            default:{
                break;
            }
        }
    }
}
void doit()
{
    if (k!=0) bfs1();
    bfs2();
    if (dep[ex][ey][1]!=0) printf("%d",dep[ex][ey][1]);
    else printf("KAKTUS");
}
int main()
{
    init();
    doit();
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值