FZU 2196 :http://acm.fzu.edu.cn/problem.php?pid=2196
题意: 给出一个起点,终点,墙壁,通路,岩浆
人先走,上下左右一次移动一格。
岩浆后走,每次向上下左右蔓延周围各一格。
问,人能否到达终点
一眼看出,附带岩浆的BFS。
思路:先将人装入队列,再将岩浆装入队列。
便具有了,一个队列,但是具有人先走岩浆后走的特性。
队列里装入的是点的位置以及,是岩浆还是人的区分变量sex。
每一次根据取出元素是人还是岩浆的不用进行不同的BFS标记操作。
book为标记数组。通路为-1,岩浆为0,墙壁也为0,人走过的点为1。则人能走的条件是,此点为-1,岩浆蔓延的条件是此点不为0(为了可以蔓延走过的1点)。
注意点: 交了一发没有过,有一个细节要注意:
假设有一个位置点X, 此点无岩浆,无人走过,所以标记为1入队。 但是之后的岩浆可能把这个位置给淹没了!! 这种情况,理论上就不能对这个点进行拓展了。
所以对每一个人放入的可走点,要加入一个判断,此点是否在放在队列等待的时间内,被岩浆覆盖了。
上BFS代码:
#include"cstdio"
#include"cstring"
#include"queue"
#include"iostream"
#include"algorithm"
using namespace std;
#define inf 1009
#define loop(x,y,z) for(x=y;x<z;x++)
int T,n,m,sx,sy,gx,gy;
char pos[inf][inf];
int book[inf][inf];
int change[4][2]={0,1,0,-1,-1,0,1,0};
struct point //存放了入队点信息,行、列、以及人走的点为1,岩浆走的点为0
{
int x,y;
int sex;
point(int i,int j,int k)
{
x=i;y=j;sex=k;
}
};
queue<point>q;
void init() //初始化函数
{
memset(book,-1,sizeof book);
while(!q.empty())q.pop();
}
int pan(int i,int j) //判断有无越界函数
{
if(i<0||i>=n||j<0||j>=m)return 0;
return 1;
}
void bfs()
{
int i,j;
loop(i,0,n)
loop(j,0,m)
if(pos[i][j]=='S') //起点入队标记,记录终点位置
{
q.push(point(i,j,1));
book[i][j]=1;
}
else if(pos[i][j]=='E')
{
gx=i;gy=j;
}
loop(i,0,n) //岩浆入队标记
loop(j,0,m)
if(pos[i][j]=='!')
{
q.push(point(i,j,0));
book[i][j]=0;
}
else if(pos[i][j]=='#')
book[i][j]=0;
while(!q.empty())
{
point t=q.front();
q.pop();
int sex=t.sex;
if(sex) //如果是人走的点
{
if(book[t.x][t.y]==0)continue; //如果这个点在队列等待时间里被岩浆淹没了,就不进行拓展了
loop(i,0,4)
{
int nowx=t.x+change[i][0];
int nowy=t.y+change[i][1];
if(pan(nowx,nowy)&&book[nowx][nowy]==-1) //合法点标记入队
{
book[nowx][nowy]=1;
q.push(point(nowx,nowy,1));
if(book[gx][gy]==1) //若终点拓展成功,输出Yes
{
printf("Yes\n");return;
}
}
}
}
else //如果是岩浆走的点
{
loop(i,0,4)
{
int nowx=t.x+change[i][0];
int nowy=t.y+change[i][1];
if(pan(nowx,nowy)&&book[nowx][nowy]!=0) //只需要标记并入队就好
{
book[nowx][nowy]=0;
q.push(point(nowx,nowy,0));
}
}
}
}
printf("No\n");
}
int main()
{
int i;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
loop(i,0,n)
scanf("%s",pos[i]);
bfs();
}
return 0;
}