Bfs 逃脱(牛客网)

题目:

这是mengxiang000和Tabris来到幼儿园的第四天,幼儿园老师在值班的时候突然发现幼儿园某处发生火灾,而且火势蔓延极快,老师在第一时间就发出了警报,位于幼儿园某处的mengxiang000和Tabris听到了火灾警报声的同时拔腿就跑,不知道两人是否能够逃脱险境? 幼儿园可以看成是一个N*M的图,在图中一共包含以下几种元素: “.”:表示这是一块空地,是可以随意穿梭的。 “#”:表示这是一块墙,是不可以走到这上边来的,但是可以被火烧毁。 “S”:表示mengxiang000和Tabris所在位子。 “E”:表示幼儿园的出口。 “*”表示火灾发源地(保证输入只有一个火灾发源地)。 已知每秒有火的地方都会向周围八个格子(上下左右、左上、右上、左下、右下)蔓延火势.mengxiang000和Tabris每秒都可以选择周围四个格子(上下左右)进行移动。(假设两人这一秒行动完之后,火势才蔓延开) 根据已知条件,判断两人能否成功逃脱险境,如果可以,输出最短逃离时间,否则输出T_T。

输入描述:

第一行输入一个整数t,表示一共的测试数据组数。 第二行输入两个整数n,m,表示幼儿园的大小。 接下来n行,每行m个字符,表示此格子是什么元素。 t<=200 3<=n<=30 3<=M<=30 保证图中有一个起点,一个出口,一个火灾源处.

输出描述:

每组数据输出一行,如果两人能够成功到达出口,那么输出最短逃离时间,否则输出T_T
示例1

输入

3
5 5
*....
.....
..S#.
...E.
.....
5 5
...#*
..#S#
...##
....E
.....
5 5
.....
S....
..*#.
...E.
.....

输出

2
T_T
T_T

解析:
  
这题乍一看挺简单(确实挺简单),但本人尝试多次竟然没有AC,异常难受~ o(TωT)o 
  一开始的思路(有误,写给自己的,可以略过):存图,然后将小盆友和火同时Bfs,嗯就是这里出问题了,火焰和人的拓展条件并不一样,所以,在入队的数量并不同,SO拓展并不是同步的!!_φ(❐_❐✧ 人丑就要多WA
  接着在网上找了个正解(https://www.cnblogs.com/zhgyki/p/9568761.html),理一下其思路:将火焰的拓展和人的拓展分隔开,先将火焰拓展,利用时间作为之后的比较中介,将火焰到达每个点的时间记录在该点(这个思路如此牛*)。接着是人的Bfs,注意遇到出口时,时间小于或等于该点火焰蔓延到的时间即可(题目说明了火焰蔓延是后滞的),然后普通的逃脱到的点的时间要严格小于火焰到达的时间。
  正解:
  1 #include <iostream>
  2 #include <cstring>
  3 #include <queue>
  4 using namespace std;
  5 typedef long long ll;
  6 #define maxn 35
  7 #define Inf 0x7fffffff
  8 int n=0,m=0,ans=Inf;
  9 int t=0;
 10 char Map[maxn][maxn];
 11 bool vis[maxn][maxn]={0};
 12 int fir[maxn][maxn]={0};//记录fire到每一格所需时间
 13 int dir[][2]={
 14     {1,0},{-1,0},{0,1},{0,-1},
 15     {1,1},{-1,-1},{-1,1},{1,-1}
 16 };
 17 struct Point{
 18     int x,y,tm;
 19     Point(){tm=0;}
 20     Point(int a,int b,int c):x(a),y(b),tm(c){}
 21 }fi,st;
 22 void FireGo()
 23 {
 24     memset(vis,false,sizeof(vis));
 25     memset(fir,0,sizeof(fir));
 26     queue<Point> q;
 27     q.push(fi);
 28     vis[fi.x][fi.y]=true;
 29     while(q.size())
 30     {
 31         Point head=q.front();
 32         q.pop();
 33         for(int i=0;i<8;++i)
 34         {
 35             int nx=head.x+dir[i][0];
 36             int ny=head.y+dir[i][1];
 37             if(nx<0||nx>=n||ny<0||ny>=m) continue;
 38             if(vis[nx][ny]) continue;
 39             vis[nx][ny]=true;
 40             fir[nx][ny]=head.tm+1;//计算每个点有火势蔓延到的时间
 41             q.push({nx,ny,head.tm+1});
 42         }
 43     }
 44 }
 45 bool Bfs()
 46 {
 47     memset(vis,0,sizeof(vis));//重新初始vis数组
 48     queue<Point> q;
 49     q.push(st);
 50     vis[st.x][st.y]=true;
 51     while(q.size())
 52     {
 53         Point head=q.front();
 54         q.pop();
 55         for(int i=0;i<4;++i)
 56         {
 57             int nx=head.x+dir[i][0];
 58             int ny=head.y+dir[i][1];
 59             if(nx<0||nx>=n||ny<0||ny>=m) continue; //越界
 60             if(vis[nx][ny]) continue;
 61             if(Map[nx][ny]=='#') continue;
 62             if(Map[nx][ny]=='E' &&head.tm+1<=fir[nx][ny])//先到出口,火才到
 63             {
 64                 //vis[nx][ny]=true;
 65                 //q.push({nx,ny,head.tm+1}); continue;
 66                  ans=head.tm+1;
 67                 return true;
 68             }
 69             if(head.tm+1<fir[nx][ny]){//要严格小于,==时本秒结束火就到
 70                 vis[nx][ny]=true;
 71                 q.push({nx,ny,head.tm+1}); 
 72             }
 73                       
 74         }
 75     }
 76     return false;
 77 }
 78 int main()
 79 {
 80     cin>>t;
 81     while(t--)
 82     {
 83         cin>>n>>m;
 84         for(int i=0;i<n;++i)
 85         for(int j=0;j<m;++j)
 86         {
 87             cin>>Map[i][j];
 88             if(Map[i][j]=='S'){
 89                 st.x=i; st.y=j;
 90             }
 91             else if(Map[i][j]=='*'){
 92                 fi.x=i; fi.y=j;
 93             }
 94         }
 95         FireGo();
 96         if(Bfs()) cout<<ans<<endl;
 97         else cout<<"T_T"<<endl;
 98     }
 99     return 0;
100 }
View Code
  错解:
 1 #include <iostream>           //不能将火 和人同时bfs()两者的拓展条件不同,入队的数量不同,导致拓展不同步
 2 #include <queue>
 3 #include <cstring>
 4 using namespace std;
 5 int n=0,m=0;
 6 char Map[30][30]={0};
 7 bool vis[30][30]={0};
 8 bool judge[30][30]={0};
 9 struct Point{
10     int x,y,tm;
11     Point(){ x=0; y=0; tm=0; }
12     Point(int a,int b,int c){ x=a; y=b; tm=c; }
13 }fi,en,st;
14 int dir[][2]={
15     {0,1},{1,0},{0,-1},{-1,0},
16     {1,1},{-1,-1},{1,-1},{-1,1} //斜方向
17 };
18 bool Check(int x,int y)//该点8方都不能有火源才安全
19 {
20     for(int i=0;i<8;++i)
21     {
22         if(Map[x+dir[i][0]][y+dir[i][1]]=='*')
23             return false;
24     }
25     return true; 
26 }
27 int bfs()//fire 和 人同时移动
28 {
29     memset(vis,false,sizeof(vis));
30     memset(judge,false,sizeof(judge));
31     queue<Point> q;
32     st.tm=0;
33     q.push(st);
34     vis[st.x][st.y]=true;   
35     while(!q.empty())
36     {
37         Point head=q.front();
38         q.pop();
39         for(int i=0;i<4;++i) //四方向遍历
40         {
41             int nx=head.x+dir[i][0];
42             int ny=head.y+dir[i][1]; 
43             if(nx<0||nx>=n||ny<0||ny>=m) continue; //越界
44             if(Map[nx][ny]=='E') return (head.tm+1); //到达出口
45             if(vis[nx][ny]) continue;
46             if(Map[nx][ny]=='#'||Map[nx][ny]=='*')  continue; //墙 火
47             if(!Check(nx,ny)) continue; //到达的点不安全
48             vis[nx][ny]=true;
49             q.push({nx,ny,head.tm+1});   
50         } 
51         if(q.empty()) return 0;
52         //火势蔓延
53         for(int i=0;i<8;++i)//这里出错,火的蔓延也应要用到队列不然其实并未伸展
54         {
55             int nx=fi.x+dir[i][0];
56             int ny=fi.y+dir[i][1];
57             judge[nx][ny]=true;
58             if(nx<0||nx>=n||ny<0||ny>=m) continue; //越界
59             if(judge[nx][ny]) continue;
60             if(Map[nx][ny]=='E') return 0; //出口被烧
61             Map[nx][ny]='*';
62         }
63     }
64     return 0;
65 }
66 int main()
67 { 
68     int t=0;
69     cin>> t;
70     while(t--)
71     {
72         cin>> n>> m;
73         for(int i=0;i<n;++i)
74         for(int j=0;j<m;++j)
75         {
76             cin>> Map[i][j];
77             if(Map[i][j]=='E'){
78                 en.x=i; en.y=j;
79             }
80             else if(Map[i][j]=='*'){
81                 fi.x=i; fi.y=j;
82             }
83             else if(Map[i][j]=='S'){
84                 st.x=i; st.y=j;
85             }
86         }
87         int temp=bfs();
88         if(temp) cout<<temp<<endl;
89         else cout<<"T_T"<<endl;
90     }
91     return 0;
92 }
View Code
 
    
    
 
     
    
 
   

猜你喜欢

转载自www.cnblogs.com/GorgeousBankarian/p/10380705.html