Fire Maze | ||||||
| ||||||
Description | ||||||
After escaping from Figo's chase, Severus falls into a N * M maze designed by Figo. At first, Severus is located on the grid S. Every second he can only move to the four grids that adjacent to the grid he is located on. The moment he move to any side of the maze, he will get rid of Figo. After T seconds, Figo will reach the maze. Because Figo is the designer of the maze, when Figo arrive, he can reach any grid if he want. If Severus can't leave the maze at that moment, there is no doubt that he will be caught by Figo. Figo is very cunning. In the maze he set not only walls, but also fire! After every second, the fire will spread to the four grid that adjacent to it. When a grid is on fire, certainly, Severus can not be on the grid. Can Severus escape from the maze? | ||||||
Input | ||||||
The first line will be a integer CS, indicating the number of test cases. In every case, there will be three integer N, M, T. After that there will be N * M characters, decribe the maze. The "." is a empty grid, "#" is wall, "F" is the fire, "S" is the initial grid that Severus stands on. 10 <= n , m <= 100 10 <= T <=10000 | ||||||
Output | ||||||
There is only one line, if Severus can get out, output the mininum time he need to escape from the maze. If he can't, output "Poor Severus must be caught by strong Figo!!!" | ||||||
Sample Input | ||||||
2 4 4 4 #### #SF# #..# #..# 3 3 4 ### #S. #.F
| ||||||
Sample Output | ||||||
3 Poor Severus must be caught by strong Figo!!! | ||||||
Source | ||||||
2014 Winter Holiday Contest 5 |
题目大意:S是起点,F是火,每一个回合火会烧到他四周的四个点,S也能走周围的四个点,问主人公是否能够逃离迷宫,(走到地图的四边就行,并且要在限制时间内)。
这里注意,火不一定只有一团,这里WA了好多发。。。
思路还是比较好确定的,双BFS,主要是要先想通先BFS谁,怎么BFS,这才是重点。这里我们先放放,首先要初始化,一会要对应思路和代码说话。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
using namespace std;//头文件
struct zuobiao
{
int x,y;
}now,nex;//坐标结构体
int step;//要输出的回合数。
queue<zuobiao>s[2];//双BFS,就要双队列。
char a[105][105];//地图。
int vis[2][105][105];//是否走过这个点的判断(这里双BFS,就要用到两个图。)
int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} };
int n,m,T;
int ok;//这里如果是1表示走到了出口,并且没有被火烧到。如果是1表示还没走到出口。
我们通过题干中的样例:
3 3 4
###
#S.
#.F
Poor Severus must be caught by strong Figo!!!能够判断出,如果S走到了出口,但是同时这个回合火烧到了出口,也是出不去的。所以我们这里确定了思路:每一个回合我都让火先烧,然后在用主人公走,烧过的地方当然是不能走的地方,如果这个时候主人公走到了没有火烧过的终点,那么他就是能够出去了。
这个时候我们对应一部分初步确定了思路的代码来详解:
void solve(int x,int y)//进来的xy是主人公的位子
{
while (!s[0].empty()) s[0].pop();//我们每一次都要清空队列
while (!s[1].empty()) s[1].pop();
memset(vis,0,sizeof(vis));//清0
vis[0][x][y]=1;
now.x=x;
now.y=y;
s[0].push(now);//我们这里规定0号队列是主人公队列。
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]=='F')//因为不止一团火,所以我们遇到一个火就push进去一个火
{
now.x=i;
now.y=j;
s[1].push(now);
vis[1][i][j]=1;
}
}
}
while((!s[0].empty())||(!s[1].empty()))
{
step++;//一个回合加1;我们稍后探讨如何确定每个回合要怎么走。
bfs1();先让火去烧
bfs();//主人公再走
if(ok==1&&step<T)//如果主人公走完之后判断能够走到出口,并且在限制时间内完成了
{
cout<<step+1<<endl;//输出回合数+1,(因为我是让火先烧的),这里好好理解一下就懂了
return ;
}
if(ok==1&&step>=T)
{
cout<<"Poor Severus must be caught by strong Figo!!!"<<endl;//如果走到了出口但是时间到了,还是相当于走不出去。
return ;
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m>>T;
int sx,sy;
for(int i=0;i<n;i++)
{
cin>>a[i];
for(int j=0;j<m;j++)
{
if(a[i][j]=='S')
{
sx=i;
sy=j;//找到主人公的位子
}
}
}
ok=0;
step=0;//初始化回合数和ok
solve(sx,sy);//进入函数
if(ok==0)
{
cout<<"Poor Severus must be caught by strong Figo!!!"<<endl;
}
}
}
我们如何确定一个回合怎么走呢?我们知道,队列中的元素是不同回合push进去的,那么我们如何确定这个回合要走多少步呢?
int sum=s.size();就可以搞定啦~这个时候测定的sum就是这个回合一共能走的点的个数。
然后while(sum--)就行啦~
火烧部分:
void bfs1()
{
int sum=s[1].size();
while(sum--)
{
now=s[1].front();
s[1].pop();
for(int i=0;i<4;i++)
{
nex.x=now.x+dir[i][0];
nex.y=now.y+dir[i][1];
if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[1][nex.x][nex.y]==0&&a[nex.x][nex.y]!='#')//火烧的就比较暴力无脑了,只要走到的地方不是墙,就尽情的让它烧吧。
{
vis[1][nex.x][nex.y]=1;
s[1].push(nex);
}
}
}
}
最后是主人公的BFS:
void bfs()
{
int sum=s[0].size();
while(sum--)
{
now=s[0].front();
s[0].pop();
for(int i=0;i<4;i++)
{
nex.x=now.x+dir[i][0];
nex.y=now.y+dir[i][1];
if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[0][nex.x][nex.y]==0&&a[nex.x][nex.y]!='#')//同样我们不能走到墙上
{
if(vis[1][nex.x][nex.y]==1)//如果走到的这个地方虽然不是墙,但是让火烧过了,其实就表明这个点不用走了。因为走了也会被烧。
continue;
s[0].push(nex);//如果没有火,就push进去。
vis[0][nex.x][nex.y]=1;
if(nex.x==0||nex.y==0||nex.x==n-1||nex.y==m-1)//如果走到了终点
{
ok=1;//ok==1;表示我走到了出口、
return ;
}
}
}
}
}
最后上完整的AC代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
using namespace std;
struct zuobiao
{
int x,y;
}now,nex;
int step;
queue<zuobiao>s[2];
char a[105][105];
int vis[2][105][105];
int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} };
int n,m,T;
int ok;
void bfs1()
{
int sum=s[1].size();
while(sum--)
{
now=s[1].front();
s[1].pop();
for(int i=0;i<4;i++)
{
nex.x=now.x+dir[i][0];
nex.y=now.y+dir[i][1];
if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[1][nex.x][nex.y]==0&&a[nex.x][nex.y]!='#')
{
vis[1][nex.x][nex.y]=1;
s[1].push(nex);
}
}
}
}
void bfs()
{
int sum=s[0].size();
while(sum--)
{
now=s[0].front();
s[0].pop();
for(int i=0;i<4;i++)
{
nex.x=now.x+dir[i][0];
nex.y=now.y+dir[i][1];
if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[0][nex.x][nex.y]==0&&a[nex.x][nex.y]!='#')
{
if(vis[1][nex.x][nex.y]==1)
continue;
s[0].push(nex);
vis[0][nex.x][nex.y]=1;
if(nex.x==0||nex.y==0||nex.x==n-1||nex.y==m-1)
{
ok=1;
return ;
}
}
}
}
}
void solve(int x,int y)
{
while (!s[0].empty()) s[0].pop();
while (!s[1].empty()) s[1].pop();
memset(vis,0,sizeof(vis));
vis[0][x][y]=1;
now.x=x;
now.y=y;
s[0].push(now);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]=='F')
{
now.x=i;
now.y=j;
s[1].push(now);
vis[1][i][j]=1;
}
}
}
while((!s[0].empty())||(!s[1].empty()))
{
step++;
bfs1();
bfs();
if(ok==1&&step<T)
{
cout<<step+1<<endl;
return ;
}
if(ok==1&&step>=T)
{
cout<<"Poor Severus must be caught by strong Figo!!!"<<endl;
return ;
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m>>T;
int sx,sy;
for(int i=0;i<n;i++)
{
cin>>a[i];
for(int j=0;j<m;j++)
{
if(a[i][j]=='S')
{
sx=i;
sy=j;
}
}
}
ok=0;
step=0;
solve(sx,sy);
if(ok==0)
{
cout<<"Poor Severus must be caught by strong Figo!!!"<<endl;
}
}
}