题目:
这是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 }
错解:
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 }