题目链接:
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;
}