J - Fire! 题目描述
乔在迷宫中工作。不幸的是,迷宫的一部分着火了,迷宫的主人没有制定火灾的逃跑计划。请帮助乔逃离迷宫。根据乔在迷宫中的位置以及迷宫的哪个方块着火,你必须确定火焰烧到他之前,乔是否可以离开迷宫,如果能离开他能跑多快。
乔和火每分钟移动一个方格,上、下、左、右,四个方向中的一个。火势向四个方向同时蔓延。乔可以从迷宫的任何一个边界逃离迷宫。无论是乔还是火都不会到达有墙的位置。
输入
第一行输入包含一个整数,即测试次数 每个测试用例的第一行包含两个 整数R和C,用空格分隔,1≤R,C≤1000
下面R行中,每一行都包含C个字符,以及每个字符是以下之一:
‘#’ 代表墙 . 代表空地,火和乔是可通行的 J 乔在迷宫中最初的位置,火和乔是可通行的 F 代表火 在每组测试中只有一个J 输出
对于每个测试用例,如果在火蔓延的时候烧到了乔,则乔无法逃出迷宫,输出’IMPOSSIBLE’。如果乔能逃出迷宫,则输出乔最快可以在几分钟内安全逃出迷宫,每组输出占一行
样例输入
2 4 4
’####
#JF#
#…#
#…#
3 3
‘###
#J.
#.F
样例输出
3
IMPOSSIBLE
题目分析:
目标:Joe逃出迷宫
阻碍条件:
1、Joe不能比火晚到或同时到同一块地方;
2、Joe不能到达墙即’#‘的位置
能实现目标的最终状态:
Joe比火先到迷宫的边缘且该处为‘.’
!!!题意中的小坑:
题干中说“在每组测试中只有一个J 输出 ”,但没说只有一个’F‘,故在一开始火可能有几处,发现这个后就可以考虑用BFS了
这题我WA了有七八次吧,稍微看了下别人的题解慢慢查错最后AC的,这里放一下我之前犯的一些错误:
1、火有多处
2、有可能墙把火和Joe完全隔开了,即火不可能到达Joe的位置,故记录火和Joe是否走过该处的book【】数组要写两个,不能像我一样企图省内存而只开了一个。
3、上面的这个book数组其实是我一开始的想法,其实我后来将记录火与Joe到达该处的步数和记录这两物是否分别已走过该处的作用都放在了该数组里,初始化该数组各数据为-1,再将火与Joe的初始位置的坐标对应的数组数据变为0,再把他们能到达的地方的步数再以此基础上增加,判断该处是否走过时只需判断该处坐标对应数组数据是否为-1就行,为-1就是没走过这。(非常棒的想法对吧,虽然是我看别人博客学来的)但是,因为在Joe开始走时,根据我上面写的阻碍条件的第二条,Joe能走到的地方,那块地方记录的Joe到达该处的步数必须小于火到达该处的步数,但是-1肯定比这些正数要小吧,如果火根本没到这,火到达该处的步数就为-1,Joe却不能走,这肯定要WA了吧,所以,在判断两物步数大小的同时,还要判断火到达该处的步数是否为-1。
然后是AC代码
//#include<iostream>
//#include<queue>
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;char maze[maxn][maxn];//迷宫
int fire[maxn][maxn],joe[maxn][maxn];//起大作用的数组
int NEXT[4][2]={
{
1,0},{
-1,0},{
0,1},{
0,-1}};//用来尝试上下左右移动的
struct node{
//把一个结构体作为一个坐标int x;int y;
};void Create(int Y,int X)
{
int i,j;for(i=1;i<=Y;i++){
for(j=1;j<=X;j++){
cin>>maze[i][j];fire[i][j]=-1;//初始化joe[i][j]=-1;}}
}void Fire_Go(int Y,int X)
{
int i,j;queue<node>q;node FIRE,temp;for(i=1;i<=Y;i++){
for(j=1;j<=X;j++){
if(maze[i][j]=='F'){
FIRE.y=i;FIRE.x=j;q.push(FIRE);//将起点放入queuefire[FIRE.y][FIRE.x]=0;//起点步数为0}}}while(q.size())//BFS基操{
FIRE=q.front();q.pop();for(i=0;i<4;i++){
temp.x=FIRE.x+NEXT[i][0];temp.y=FIRE.y+NEXT[i][1];if(fire[temp.y][temp.x]!=-1)continue;//已走过if(maze[temp.y][temp.x]=='#')continue;//撞墙if(temp.x>X||temp.x<1||temp.y>Y||temp.y<1)continue;//火不可超出边界fire[temp.y][temp.x]=fire[FIRE.y][FIRE.x]+1;//步数+1q.push(temp);}}
}int Joe_Go(int Y,int X)
{
int i,j,flag;queue<node>q;node per,temp;//per即personfor(i=1,flag=0;i<=Y;i++){
for(j=1;j<=X;j++){
if(maze[i][j]=='J'){
per.x=j;per.y=i;//记录Joe的位置joe[per.y][per.x]=0;//起点步数为0q.push(per);//放入队列flag=1;//做个标记,方便跳出循环break;}}if(flag){
break;}}while(q.size()){
per=q.front();q.pop();for(i=0;i<4;i++){
temp.x=per.x+NEXT[i][0];temp.y=per.y+NEXT[i][1];if(temp.x>X||temp.x<1||temp.y>Y||temp.y<1)//能超出边界,说明能逃出迷宫{
return joe[per.y][per.x]+1;//此时该处的步数还未算出来,故这么处理//在此处就应该跳出}if(fire[temp.y][temp.x]<=joe[per.y][per.x]+1&&fire[temp.y][temp.x]!=-1)continue;//高度注意这里的"&&fire[temp.y][temp.x]!=-1",必须写if(joe[temp.y][temp.x]!=-1)continue;//已走过if(maze[temp.y][temp.x]=='#')continue;//撞墙joe[temp.y][temp.x]=joe[per.y][per.x]+1;//步数+1q.push(temp);}}return -1;//队列为空但仍未找到出口,说明不能出去,此时while循环结束,直接return一个负数方便判断
}int main()
{
int T,ans,Y,X;cin>>T;while(T--){
cin>>Y>>X;Create(Y,X);//创造地图Fire_Go(Y,X);//火先走,把火走到各位置的步数记录下来ans=Joe_Go(Y,X);//Joe走,获得返回值if(ans<0)//人没了{
cout<<"IMPOSSIBLE"<<endl;}else//人有了{
cout<<ans<<endl;}}return 0;
}