穿越(BFS)

题目描述

亚马逊雨林实在是太大了,小X和他的小弟们进去一会儿就迷路了,然而大雨已经来临,冲刷了一些道路,小X凭借他最后的5%的电量给你发来一条求助信息,希望你帮助他们逃出困境……

小X给你发来一张n×m的地图,每一个点有4种情况。

“0”:此地方可以走。

“1”:此地方不可以走。

“2”:此地方有一种凶恶的野兽。

“3”:此地方为传送地域。

野兽会不定时地苏醒过来,此阶段该处就不能走。 暴雨会不定时地冲刷一些地区,这些地区从今往后不可以行走,也不可以传送到。 传送地域之间可以互相传送,即可以从一个传送门传送到任何一个其他的传送门。 小X和他的小弟们现在位于(1,1),他们希望在(n,m)点逃出雨林。 他们只能前后左右移动,每移动一次需要花费1个单位的时间,传送一次需要花费2个单位的时间,也可以选择不传送。 注意:若下一秒某地区暴雨即将冲刷/野兽即将醒来,则不可以通行,也不可停留在这个这个地区。 在任意时刻,他们可以选择不进行任何操作。

输入格式

第一行两个整数n,m,表示一张n×m的地图。

接下来n行,每行m个整数,为0-3之间的一个数字。

接下来一行一个整数a, 表示接下来a行描述暴雨情况。

接下来a行,每行第一个整数为t,表示此次暴雨在t时刻来临;第二个整数为p,表示此次暴雨冲刷了p个地区;接下来p组整数,每组有(x,y)两个整数,表示(x,y)这个地点被冲刷。(假设暴雨冲刷不需要时间,同一个地点可能被暴雨多次冲刷)

接下来b行,每行前两个整数为t1,t2,表示这个野兽在t1-t2时刻是苏醒的。

接下来两个整数x,y,表示野兽位于x,y位置。(保证(x,y)=2) 不保证所有的野兽均会有苏醒的时刻 保证:(1,1)=(n,m)=0且永远不会被暴雨冲刷。

输出格式

一行一个整数,即最短逃脱时间。 (保证小X和他的小弟们可以逃脱亚马逊雨林)

样例

输入样例

3 3
0 1 0
2 0 1
3 2 0
2
2 1 3 1
1 1 1 3
1
2 4 2 1

输出样例

4

数据范围与提示

时刻1,暴雨冲刷了1,3这个位置。 时刻2,暴雨冲刷了3,1这个位置。 时刻2-4,位于(2,1)的野兽苏醒了。 小X与他的小弟们的逃脱路线: (1,1)->(2,1)->(2,2)->(3,2)->(3,3)

对于100%的数据,n≤300,m≤300,t≤10000。

思路

这题暴力BFS就好了,但是码量有亦点点的大。

BFS是可以重复入队的,但为了不让他们反复横跳,就要判断时间,取时间的较小值。注意,只有时间发生改变了需要入队。

BFS内部要分类:

  • 处理传送门(注意:传送门会被洪水冲坏)

  • 判断下一步是否会被洪水干掉/出界/阻挡

  • 下一步空地或传送门

    1.更新

  • 下一步野兽

    1.判断是否等待(不等待就更新,等待就进入下一步)

    2.判断等待是会不会被干掉(野兽或洪水)

    3.更新(记得加上等待时间)

注意,更新都需要判断时间 共169行,请勿COPY!!!

CODE

#include<bits/stdc++.h>
using namespace std;

int ax[5]={0,1,-1,0,0},ay[5]={0,0,0,1,-1};
int mp[400][400],tim[400][400],fx[90010],fy[90010];
int cnt;
struct node
{
    int x,y;
}csm[90005];
struct node1
{
    int st,en,many;
}eat[400][400];
int n,ys,by,m,rain[400][400];

void in()//输入
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&mp[i][j]);
            if(mp[i][j]==3)
            {
                cnt++;
                csm[cnt].x=i;
                csm[cnt].y=j;
            }
        }
    }
    //地图和传送门
    scanf("%d",&by);
    for(int i=1;i<=by;i++)
    {
        int t,p;
        scanf("%d%d",&t,&p);
        for(int j=1;j<=p;j++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(rain[x][y])
            {
                rain[x][y]=min(rain[x][y],t);
            }
            else
            {
                rain[x][y]=t;
            }
        }
    }
    //暴雨
    scanf("%d",&ys);
    for(int j=1;j<=ys;j++)
    {
        int x,y,t1,t2;
        scanf("%d%d%d%d",&t1,&t2,&x,&y);
        eat[x][y].many++;
        eat[x][y].st=t1;
        eat[x][y].en=t2;
    }
    //野兽
}
int wait(int x,int y,int t,int x1,int y1)//等待时间
{
    int k=0;
    if(eat[x][y].st<=t&&eat[x][y].en>=t)
    {
        int tmp=eat[x][y].en+1;
        if(rain[x1][y1]<=tmp&&rain[x1][y1]) return -1;//洪水
        else if(eat[x1][y1].st<=tmp&&eat[x1][y1].en>=tmp) return -1;//野兽
        else return tmp-t;//返回等待时间
    }
    else return 0;//不须等待
}
void bfs(int x,int y)
{
    int t=0,w=1;
    fx[w]=x;
    fy[w]=y;
    while(t<w)
    {
        t++;
        if(mp[fx[t]][fy[t]]==3)//当前传送门!!!
        {
            for(int i=1;i<=cnt;i++)
            {
                if(rain[csm[i].x][csm[i].y]&&rain[csm[i].x][csm[i].y]<=tim[fx[t]][fy[t]]+2) continue;//被洪水冲垮了
                if(tim[csm[i].x][csm[i].y]==0)
                {
                    tim[csm[i].x][csm[i].y]=tim[fx[t]][fy[t]]+2;
                    w++;
                    fx[w]=csm[i].x;
                    fy[w]=csm[i].y;
                }
                else if(tim[csm[i].x][csm[i].y]>0)
                {
                    if(tim[csm[i].x][csm[i].y]>tim[fx[t]][fy[t]]+2)
                    {
                        tim[csm[i].x][csm[i].y]=tim[fx[t]][fy[t]]+2;
                        w++;
                        fx[w]=csm[i].x;
                        fy[w]=csm[i].y;
                    }
                }//更新
            }
        }
        for(int i=1;i<=4;i++)
        {
            x=fx[t]+ax[i];
            y=fy[t]+ay[i];//下一步
            if(x<=0||y<=0||x>n||y>m) continue;//出界
            if(mp[x][y]==1) continue;//阻挡
            if(rain[x][y]<=tim[fx[t]][fy[t]]+1&&rain[x][y]) continue;//洪水
            if(mp[x][y]==2)//野兽
            {
                int tmp=wait(x,y,tim[fx[t]][fy[t]]+1,fx[t],fy[t]);//计算等待时间
                if(tmp==-1) continue;//此路不通
                else
                {
                    if(tim[x][y]==0&&(x!=1||y!=1))//判断为0
                    {
                        w++;
                        fx[w]=x;
                        fy[w]=y;
                        tim[x][y]=tim[fx[t]][fy[t]]+1+tmp;
                    }
                    else
                    {
                        if(tim[x][y]>tim[fx[t]][fy[t]]+1+tmp)//时间
                        {
                            tim[x][y]=tim[fx[t]][fy[t]]+1+tmp;
                            w++;
                            fx[w]=x;
                            fy[w]=y;
                        }
                    }//更新
                }
            }
            else if(mp[x][y]==0||mp[x][y]==3)//空地和传送门(下一步)
            {
                if(tim[x][y]==0&&(x!=1||y!=1))//判断为0
                {
                    w++;
                    fx[w]=x;
                    fy[w]=y;
                    tim[x][y]=tim[fx[t]][fy[t]]+1;
                }
                else if(x!=1||y!=1)
                {
                    if(tim[x][y]>tim[fx[t]][fy[t]]+1)//时间
                    {
                        tim[x][y]=tim[fx[t]][fy[t]]+1;
                        w++;
                        fx[w]=x;
                        fy[w]=y;
                    }
                }
            }
        }
    }
}
int main()
{
    in();
    bfs(1,1);
    printf("%d",tim[n][m]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值