福州大学校赛G FZU FOJ Escape 两次BFS 或者一次BFS

题目链接:
 
 
Problem 2196 Escape

Accept: 97    Submit: 537
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

小明进入地下迷宫寻找宝藏,找到宝藏后却发生地震,迷宫各处产生岩浆,小明急忙向出口处逃跑。如果丢下宝藏,小明就能迅速离开迷宫,但小明并不想轻易放弃自己的辛苦所得。所以他急忙联系当程序员的朋友你(当然是用手机联系),并告诉你他所面临的情况,希望你能告诉他是否能成功带着宝藏逃脱。

Input

有多组测试数据。

每组测试数据第一行是一个整数T,代表接下去的例子数。(0<=T<=10)

接下来是T组例子。

每组例子第一行是两个整数N和M。代表迷宫的大小有N行M列(0<=N,M<=1000)。

接下来是一个N*M的迷宫描述。

S代表小明的所在地。

E代表出口,出口只有一个。

.代表可以行走的地方。

!代表岩浆的产生地。(这样的地方会有多个,其个数小于等于10000)

#代表迷宫中的墙,其不仅能阻挡小明前进也能阻挡岩浆的蔓延。

小明携带者宝藏每秒只能向周围移动一格,小明不能碰触到岩浆(小明不能和岩浆处在同一格)。

岩浆每秒会向四周不是墙的地方蔓延一格。

小明先移动完成后,岩浆才会蔓延到对应的格子里。

小明能移动到出口,则小明顺利逃脱。

Output

每组测试数据输出只有一行“Yes”或者“No”。 “Yes”代表小明可以成功逃脱。否则输出“No”。

Sample Input

35 5....!S....#....!#...#E...2 2S.!E2 2SE!.

Sample Output

YesNoYes

Source

福州大学第十二届程序设计竞赛 




/*
方法一<a><a>
链接:</a></a>http://acm.fzu.edu.cn/problem.php?pid=2196
题意:问小明能不能顺利到达出口。小明和岩浆每秒都会向四周移动一格(“小明先于岩浆”)。
分析:BFS。先BFS预处理每个格子岩浆到达的时间(令其为d[i][j]);
    再BFS小明到达终点的路径,对每一个格子
    ①如果它是终点,则要求小明在<=d[i][j]的时间内到达;
    ②如果它不是终点,则要求小明在<d[i][j]的时间内到达;
*/
#include<vector>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
struct D
{
    int x,y,dist;  //xy坐标,对于init中的岩浆dist代表岩浆到达的时间,对于bfs_ans中的人代表走到此处的时间
    D(int x=0,int y=0,int dist=0):x(x),y(y),dist(dist){}  
};
queue<D>qd;
int flag,sx,sy,n,m,fire,d[1005][1005],vis[1005][1005],dir[4][2]={{0,1},{1,0},{-1,0},{0,-1} };
char G[1005][1005];
bool judge(int x,int y)
{
    if(!vis[x][y]&&x>=0&&x<=n&&y>=0&&y<m&&G[x][y]!='#') return true;
    else return false;
}
void init()
{
    memset(d,0,sizeof(d));
    memset(vis,0,sizeof(vis));
    while(!qd.empty()){
        D cur=qd.front();
        qd.pop();
        for(int i=0;i<4;i++)
        {
            D next;
            next.x=cur.x+dir[i][0];
            next.y=cur.y+dir[i][1];
            next.dist=cur.dist+1;
            if(judge(next.x,next.y)) {
                d[next.x][next.y]=next.dist; //岩浆到达的时间
                qd.push(next); //下一个岩浆
                vis[next.x][next.y]=1; //只一次
            }
        }
    }
}
void bfs_ans(int x,int y)
{
    while(!qd.empty()) qd.pop();
    D star;star.x=x;star.y=y;
    qd.push(star);
    while(!qd.empty()){
        D cur=qd.front();
        qd.pop();
        if(G[cur.x][cur.y]=='E') {flag=1;return ;}//到达
        for(int i=0;i<4;i++)
        {
            D next;
            next.x=cur.x+dir[i][0];
            next.y=cur.y+dir[i][1];
            next.dist=cur.dist+1;
            if(judge(next.x,next.y)&&(d[next.x][next.y]>next.dist ||(G[next.x][next.y]=='E'&&d[next.x][next.y]>=next.dist ) )) {//小明先于岩浆,所以,如果是终点处,可以与岩浆到达时间相同
                qd.push(next);vis[next.x][next.y]=1;
            }
        }
    }
    return ;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        while(!qd.empty()) qd.pop();
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%s",G[i]);
        fire=0;flag=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            {
                if(G[i][j]=='S') {sx=i;sy=j;}//起点
                if(G[i][j]=='!') {fire++;qd.push(D(i,j,0));d[i][j]=0; } //岩浆入队列
            }
        if(fire>0) init();//预处理每个格子岩浆到达的时间
        memset(vis,0,sizeof(vis));
        bfs_ans(sx,sy);//bfs答案
        if(flag) puts("Yes");
        else puts("No");
    }
    return 0;
}
 
 
 
/*
方法2:
此为同学代码,一次DFS,将人和所有岩浆第一次直接进队列,然后BFS走动,每走一个,装进队尾
即每一步都是:人走一步,所有岩浆蔓延一步,而且新岩浆加入队列
方法和一般的路径搜索一样,这里有多个源点,有几个地方要根据题目的要求处理,不然容易错
m,n可以为0;人先动,对非终点,人不能到岩浆即将到的地方,终点直接逃脱;
岩浆会覆盖空地和人走过的地方,而终点没事
*/
#include <cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
#include<string>
#include<algorithm>
#include<vector>
#define LL long long
const int maxn=1010;
using namespace std;
struct node
{
   int h,l,r;//r判断是否是人
   node(int hh,int ll,int rr)
   {
       h=hh;
       l=ll;
       r=rr;
   }
   node() {}
};
char ma[maxn][maxn];
int n,m;
int dir[4][2]= {{0,1},{-1,0},{0,-1},{1,0}};
queue<node>qu;
bool judge(int h,int l)
{
   for(int i=0; i<4; i++)
       if(ma[h+dir[i][0]][l+dir[i][1]]=='!')
           return 0;
   return 1;
}
int bfs()
{
   node st;
   int h,l,hh,ll;
   while(!qu.empty())
   {
       st=qu.front();
       qu.pop();
       h=st.h;
       l=st.l;
       for(int i=0; i<4; i++)
       {
           hh=h+dir[i][0];
           ll=l+dir[i][1];
           if(0<=hh&&hh<n&&0<=ll&&ll<m&&
                   ma[hh][ll]!='!'&&ma[hh][ll]!='#')
           {
               if(st.r&&ma[hh][ll]=='E')return 1;//人在火山灰之前到达,逃出
               if(st.r&&ma[hh][ll]=='.'&&judge(hh,ll))//下一步能到达之后不会出现岩浆
               {
                   ma[hh][ll]='S';
                   qu.push(node(hh,ll,1));
               }
               if(!st.r)//岩浆
               {
                   if(ma[hh][ll]=='E')return 0;
                   ma[hh][ll]='!';//直接标记上岩浆
                   qu.push(node(hh,ll,0));
               }
           }
       }
   }
   return 0;
}
int main(void)
{
   int t;
   scanf("%d", &t);
   while (t--)
   {
       while(!qu.empty())qu.pop();
       scanf("%d%d",&n,&m);
       for (int i = 0; i<n; i++)scanf("%s",ma[i]);
       if(m!=0&&n!=0)
       {
           for (int i = 0; i<n; i++)
               for(int j=0; j<m; j++)
                   if(ma[i][j]=='S')//先放人
                       qu.push(node(i,j,1));
           for (int i = 0; i<n; i++)
               for(int j=0; j<m; j++)
                   if(ma[i][j]=='!')
                       qu.push(node(i,j,0));
       }
       if(bfs())
           printf("Yes\n");
       else
           printf("No\n");
   }
   return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值