UVA11624-Fire!
继续刷邝斌飞搜索专题
UVA11624 (这个邝斌给的链接,但现在UVA官网只能进主页,题目页换新地址了,需要开tizi,懒得开,直接看洛谷吧)
再一次印证原汁原味英文比翻译好,真按照翻译里的这句:“当Joe走到一个迷宫的边界格子时,我们认为他已经出了迷宫”,那第一个样例就应该输出2,同类人
之前学过复杂度,从0开始回顾但不是这时候,感觉这玩意刷点题再回顾比较好,目前为止都是看到题有啥思路就直接写,没管过复杂度的事
读完题感觉又是相当简单啊
艹写完TLE了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //之前调试代码感觉思维变得缜密了,些许慰藉 2 #include<stdio.h> 3 #include<iostream> 4 #include<string.h> 5 using namespace std; 6 char map[1000][1000]; 7 #include<queue> 8 int T; 9 int R,C; 10 int Jx,Jy; 11 int Fx,Fy; 12 struct Node{ 13 int x; 14 int y; 15 int step; 16 char thismap[1000][1000]; 17 }; 18 int vis[1001][1001];//由于有vis[Jx][Jy]=1;这句话出现,要开多一个 19 Node firstnode; 20 Node thisnode; 21 Node nextnode; 22 queue<Node>q; 23 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; 24 int flag; 25 int legal(int x,int y); 26 int main() 27 { 28 // freopen("zhishu.txt","r",stdin); 29 cin>>T; 30 while(T--){ 31 memset(vis,0,sizeof(vis)); 32 while(!q.empty()) 33 q.pop(); 34 flag=0; 35 cin>>R>>C; 36 getchar(); 37 for(int i=0;i<R;i++){ 38 for(int j=0;j<C;j++){ 39 cin>>map[i][j]; 40 firstnode.thismap[i][j]=map[i][j]; 41 if(map[i][j]=='J'){ 42 Jx=i; 43 Jy=j; 44 } 45 if(map[i][j]=='F'){ 46 Fx=i; 47 Fy=j; 48 } 49 } 50 getchar(); 51 } 52 vis[Jx][Jy]=1; 53 firstnode.x=Jx; 54 firstnode.y=Jy; 55 firstnode.step=0; 56 q.push(firstnode); 57 58 while(!q.empty()){ 59 if(flag==1) 60 break; 61 thisnode=q.front(); 62 q.pop(); 63 for(int i=0;i<4;i++){ 64 nextnode.x=thisnode.x+dir[i][0]; 65 nextnode.y=thisnode.y+dir[i][1]; 66 if(!legal(nextnode.x,nextnode.y)){//不用走了,能出去,直接输出 67 cout<<thisnode.step+1<<endl; 68 flag=1; 69 break; 70 } 71 if(legal(nextnode.x,nextnode.y)){//发现可以走 72 for(int i=0;i<R;i++)//先别走,更新下着火地图,找到着火的F点,就四个方向都着火,即搞为F 73 for(int j=0;j<C;j++) 74 nextnode.thismap[i][j]=thisnode.thismap[i][j]; 75 76 for(int i=0;i<R;i++) 77 for(int j=0;j<C;j++) 78 if(thisnode.thismap[i][j]=='F') 79 for(int k=0;k<4;k++) 80 if(legal(i+dir[k][0],j+dir[k][1])) 81 if(thisnode.thismap[i+dir[k][0]][j+dir[k][1]]=='.') 82 nextnode.thismap[i+dir[k][0]][j+dir[k][1]]='F'; 83 84 //地图已经更新,开始走 85 // 这个时候地图要用nextnode.thismap.但注意此时点还是nextnode.x和y 86 if(nextnode.thismap[nextnode.x][nextnode.y]=='.'){ 87 vis[nextnode.x][nextnode.y]=1; 88 nextnode.step=thisnode.step+1; 89 // cout<<nextnode.x<<" "<<nextnode.y<<endl; 90 q.push(nextnode); 91 } 92 } 93 } 94 } 95 if(flag==0) 96 cout<<"IMPOSSIBLE"<<endl; 97 } 98 } 99 int legal(int x,int y) 100 { 101 if(0<=x&&x<R&&0<=y&&y<C) 102 return 1; 103 else 104 return 0; 105 }
我着火更新每次重新都遍历的一遍(就是每个点是个包涵thismap的结构体,出队的点,四个方向走的时候,看当前是啥状态,R*C整个thisnode的thismap地图,跑一遍,如果是'F',就四周起火,赋给新的nextnode的thismap),估计这里TLE了
题解说双BFS,参考博客,小启发:BFS先跑一遍这个点几步之后会着火
但好奇怪啊,R*C遍历,是F,就压入着火搜索队列,百度查广搜时间复杂度是m+n,那这R*C*(R+C)已经10^9了,如果T是10组数据那就10^10超时了呀
依旧TLE
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 using namespace std; 5 char map[1000][1000]; 6 #include<queue> 7 int T; 8 int R,C; 9 int Jx,Jy; 10 struct Node{ 11 int x; 12 int y; 13 int step; 14 }; 15 int vis[1001][1001];//由于有vis[Jx][Jy]=1;这句话出现,要开多一个 16 Node firstnode; 17 Node thisnode; 18 Node nextnode; 19 queue<Node>q; 20 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; 21 int flag; 22 int legal(int x,int y); 23 void bfs_F(int x,int y); 24 int how_many_steps_F[1001][10001];//多少步后点(x,y)会起火 25 26 int main() 27 { 28 // freopen("zhishu.txt","r",stdin); 29 cin>>T; 30 while(T--){ 31 memset(vis,0,sizeof(vis)); 32 memset(how_many_steps_F,1,sizeof(how_many_steps_F)); 33 while(!q.empty()) 34 q.pop(); 35 flag=0; 36 cin>>R>>C; 37 getchar(); 38 for(int i=0;i<R;i++){ 39 for(int j=0;j<C;j++){ 40 cin>>map[i][j]; 41 if(map[i][j]=='J'){ 42 Jx=i; 43 Jy=j; 44 } 45 } 46 getchar(); 47 } 48 49 for(int i=0;i<R;i++) 50 for(int j=0;j<C;j++){ 51 if(map[i][j]=='F'){ 52 memset(vis,0,sizeof(vis)); 53 firstnode.x=i; 54 firstnode.y=j; 55 firstnode.step=0; 56 //用不到thismap 57 q.push(firstnode); 58 bfs_F(i,j);//着火搜索,借用q队列和vis 59 } 60 } 61 62 memset(vis,0,sizeof(vis));//清vis,准备给下面J开始行走用 63 vis[Jx][Jy]=1; 64 firstnode.x=Jx; 65 firstnode.y=Jy; 66 firstnode.step=0; 67 q.push(firstnode); 68 69 while(!q.empty()){ 70 if(flag==1) 71 break; 72 thisnode=q.front(); 73 q.pop(); 74 for(int i=0;i<4;i++){ 75 nextnode.x=thisnode.x+dir[i][0]; 76 nextnode.y=thisnode.y+dir[i][1]; 77 if(!legal(nextnode.x,nextnode.y)){//不用走了,能出去,直接输出 78 cout<<thisnode.step+1<<endl; 79 flag=1; 80 break; 81 } 82 if(legal(nextnode.x,nextnode.y)){//发现可以走 83 84 if(map[nextnode.x][nextnode.y]=='.'&&how_many_steps_F[nextnode.x][nextnode.y]>thisnode.step+1&&vis[nextnode.x][nextnode.y]==0){//如果在我之前就着火了,或者即将着火 85 // 如果可以走,即将踏出的这一步之前 86 // 先看这一步踏出后是不是着火 87 // 既不能往已经着火的点里跳,也不能往踏出一步后才会着火的点里跳 88 89 vis[nextnode.x][nextnode.y]=1; 90 nextnode.step=thisnode.step+1; 91 q.push(nextnode); 92 } 93 } 94 } 95 } 96 if(flag==0) 97 cout<<"IMPOSSIBLE"<<endl; 98 } 99 } 100 int legal(int x,int y) 101 { 102 if(0<=x&&x<R&&0<=y&&y<C) 103 return 1; 104 else 105 return 0; 106 } 107 void bfs_F(int x,int y) 108 { 109 while(!q.empty()){ 110 thisnode=q.front(); 111 q.pop(); 112 for(int i=0;i<4;i++){ 113 if(legal(thisnode.x+dir[i][0],thisnode.y+dir[i][1])){ 114 nextnode.x=thisnode.x+dir[i][0]; 115 nextnode.y=thisnode.y+dir[i][1]; 116 if(map[nextnode.x][nextnode.y]=='.'){ 117 if(vis[nextnode.x][nextnode.y]==0){ 118 vis[nextnode.x][nextnode.y]=1; 119 nextnode.step=thisnode.step+1; 120 if(how_many_steps_F[nextnode.x][nextnode.y]>nextnode.step){ 121 how_many_steps_F[nextnode.x][nextnode.y]=nextnode.step; 122 // cout<<"!"<<nextnode.x<<" "<<nextnode.y<<" "<<how_many_steps_F[nextnode.x][nextnode.y]<<endl; 123 q.push(nextnode); 124 } 125 } 126 } 127 } 128 } 129 } 130 }
我着火bfs是遍历一遍R*C,遇到F就bfs,但看上面超链接里的双BFS博客,是记录下有几个F,一起压进去,记得之前测过,空跑for10^9也会很久,所以估计这里for遍历R*C的时候,10^6先整个进来,就在时间上有点不优秀了
想想也确实,我是刷了好几次,F着火地图,有几个就去BFS一次,更新最少着火的how_many_steps_F,vis自然也用了好几次,而双BFS博客里是就刷一遍,vis只用一遍
麻痹的,具体时间复杂度我也不懂啊,但感觉会更优化,先按照题解里说的,把所有F都提前存好的这招试试吧
但有更深的感悟就是,写的跟一坨屎的代码思路基本都不是正解,正解基本都清清爽爽
妈的写完还是TLE
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 using namespace std; 5 char map[1000][1000]; 6 #include<queue> 7 int T; 8 int R,C; 9 int Jx,Jy; 10 struct Node{ 11 int x; 12 int y; 13 int step; 14 }; 15 int vis[1001][1001];//由于有vis[Jx][Jy]=1;这句话出现,要开多一个 16 Node firstnode; 17 Node thisnode; 18 Node nextnode; 19 queue<Node>q; 20 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; 21 int flag; 22 int legal(int x,int y); 23 void bfs_F(); 24 int how_many_steps_F[1001][10001];//多少步后点(x,y)会起火 25 int num_of_F; 26 int Fx[1000]; 27 int Fy[1000];//Fx[0]=7,Fy[0]=3 表示,第0个F坐标为(7,3) 28 int main() 29 { 30 // freopen("zhishu.txt","r",stdin); 31 cin>>T; 32 while(T--){ 33 num_of_F=0; 34 memset(Fx,0,sizeof(Fx)); 35 memset(Fy,0,sizeof(Fy)); 36 memset(vis,0,sizeof(vis)); 37 memset(how_many_steps_F,1,sizeof(how_many_steps_F)); 38 while(!q.empty()) 39 q.pop(); 40 flag=0; 41 cin>>R>>C; 42 getchar(); 43 for(int i=0;i<R;i++){ 44 for(int j=0;j<C;j++){ 45 cin>>map[i][j]; 46 if(map[i][j]=='J'){ 47 Jx=i; 48 Jy=j; 49 } 50 if(map[i][j]=='F'){ 51 Fx[num_of_F]=i; 52 Fy[num_of_F]=j; 53 num_of_F++;//比如总共3个F,那num_of_F是3 54 } 55 } 56 getchar(); 57 } 58 59 bfs_F();//着火搜索,借用q队列和vis 60 61 62 memset(vis,0,sizeof(vis));//清vis,准备给下面J开始行走用 63 vis[Jx][Jy]=1; 64 firstnode.x=Jx; 65 firstnode.y=Jy; 66 firstnode.step=0; 67 q.push(firstnode); 68 69 while(!q.empty()){ 70 if(flag==1) 71 break; 72 thisnode=q.front(); 73 q.pop(); 74 for(int i=0;i<4;i++){ 75 nextnode.x=thisnode.x+dir[i][0]; 76 nextnode.y=thisnode.y+dir[i][1]; 77 if(!legal(nextnode.x,nextnode.y)){//不用走了,能出去,直接输出 78 cout<<thisnode.step+1<<endl; 79 flag=1; 80 break; 81 } 82 if(legal(nextnode.x,nextnode.y)){//发现可以走 83 84 if(map[nextnode.x][nextnode.y]=='.'&&how_many_steps_F[nextnode.x][nextnode.y]>thisnode.step+1&&vis[nextnode.x][nextnode.y]==0){//如果在我之前就着火了,或者即将着火 85 // 如果可以走,即将踏出的这一步之前 86 // 先看这一步踏出后是不是着火 87 // 既不能往已经着火的点里跳,也不能往踏出一步后才会着火的点里跳 88 89 vis[nextnode.x][nextnode.y]=1; 90 nextnode.step=thisnode.step+1; 91 q.push(nextnode); 92 } 93 } 94 } 95 } 96 if(flag==0) 97 cout<<"IMPOSSIBLE"<<endl; 98 } 99 } 100 int legal(int x,int y) 101 { 102 if(0<=x&&x<R&&0<=y&&y<C) 103 return 1; 104 else 105 return 0; 106 } 107 void bfs_F() 108 { 109 for(int i=0;i<num_of_F;i++){ 110 firstnode.x=Fx[i]; 111 firstnode.y=Fy[i]; 112 firstnode.step=0; 113 q.push(firstnode); 114 } 115 while(!q.empty()){ 116 117 thisnode=q.front(); 118 q.pop(); 119 for(int i=0;i<4;i++){ 120 nextnode.x=thisnode.x+dir[i][0]; 121 nextnode.y=thisnode.y+dir[i][1]; 122 if(legal(nextnode.x,nextnode.y)&&map[nextnode.x][nextnode.y]=='.'&&vis[nextnode.x][nextnode.y]==0){ 123 vis[nextnode.x][nextnode.y]=1; 124 nextnode.step=thisnode.step+1; 125 how_many_steps_F[nextnode.x][nextnode.y]=nextnode.step; 126 q.push(nextnode); 127 } 128 } 129 } 130 }
哦草,惊着我了,数组开大点就AC了!!!
仔细检查发现一点问题没有
AC代码
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 using namespace std; 5 char map[1000][1000]; 6 #include<queue> 7 int T; 8 int R,C; 9 int Jx,Jy; 10 struct Node{ 11 int x; 12 int y; 13 int step; 14 }; 15 int vis[1001][1001];//由于有vis[Jx][Jy]=1;这句话出现,要开多一个 16 Node firstnode; 17 Node thisnode; 18 Node nextnode; 19 queue<Node>q; 20 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; 21 int flag; 22 int legal(int x,int y); 23 void bfs_F(); 24 int how_many_steps_F[1000][1000];//多少步后点(x,y)会起火 开小了会RE 25 int num_of_F; 26 int Fx[150];//开小了会TLE,不能再小了 记录着有多少个F,这题我测试发现,有超过100个但不到150个的F,直接开了150个肯定够了 这个跟之前提过的一样,开小了会出现RE/TLE各种报错,针对这个来说就是如果开了100个,会有类似把值赋给Fx[110]的操作导致TLE.但之前记得字符串数组越界没啥事,暂且搁置不管那个了 27 int Fy[150];//Fx[0]=7,Fy[0]=3 表示,第0个F坐标为(7,3) 28 int main() 29 { 30 // freopen("zhishu.txt","r",stdin); 31 cin>>T; 32 while(T--){ 33 num_of_F=0; 34 memset(Fx,0,sizeof(Fx)); 35 memset(Fy,0,sizeof(Fy)); 36 memset(vis,0,sizeof(vis)); 37 memset(how_many_steps_F,1,sizeof(how_many_steps_F)); 38 while(!q.empty()) 39 q.pop(); 40 flag=0; 41 cin>>R>>C; 42 getchar(); 43 for(int i=0;i<R;i++){ 44 for(int j=0;j<C;j++){ 45 cin>>map[i][j]; 46 if(map[i][j]=='J'){ 47 Jx=i; 48 Jy=j; 49 } 50 if(map[i][j]=='F'){ 51 Fx[num_of_F]=i; 52 Fy[num_of_F]=j; 53 num_of_F++;//比如总共3个F,那num_of_F是3 54 } 55 } 56 getchar(); 57 } 58 59 bfs_F();//着火搜索,借用q队列和vis 60 61 62 memset(vis,0,sizeof(vis));//清vis,准备给下面J开始行走用 63 vis[Jx][Jy]=1; 64 firstnode.x=Jx; 65 firstnode.y=Jy; 66 firstnode.step=0; 67 q.push(firstnode); 68 69 while(!q.empty()){ 70 if(flag==1) 71 break; 72 thisnode=q.front(); 73 q.pop(); 74 for(int i=0;i<4;i++){ 75 nextnode.x=thisnode.x+dir[i][0]; 76 nextnode.y=thisnode.y+dir[i][1]; 77 if(!legal(nextnode.x,nextnode.y)){//不用走了,能出去,直接输出 78 cout<<thisnode.step+1<<endl; 79 flag=1; 80 break; 81 } 82 if(legal(nextnode.x,nextnode.y)){//发现可以走 83 84 if(map[nextnode.x][nextnode.y]=='.'&&how_many_steps_F[nextnode.x][nextnode.y]>thisnode.step+1&&vis[nextnode.x][nextnode.y]==0){//如果在我之前就着火了,或者即将着火 85 // 如果可以走,即将踏出的这一步之前 86 // 先看这一步踏出后是不是着火 87 // 既不能往已经着火的点里跳,也不能往踏出一步后才会着火的点里跳 88 89 vis[nextnode.x][nextnode.y]=1; 90 nextnode.step=thisnode.step+1; 91 q.push(nextnode); 92 } 93 } 94 } 95 } 96 if(flag==0) 97 cout<<"IMPOSSIBLE"<<endl; 98 } 99 } 100 int legal(int x,int y) 101 { 102 if(0<=x&&x<R&&0<=y&&y<C) 103 return 1; 104 else 105 return 0; 106 } 107 void bfs_F() 108 { 109 for(int i=0;i<num_of_F;i++){ 110 firstnode.x=Fx[i]; 111 firstnode.y=Fy[i]; 112 firstnode.step=0; 113 q.push(firstnode); 114 } 115 while(!q.empty()){ 116 117 thisnode=q.front(); 118 q.pop(); 119 for(int i=0;i<4;i++){ 120 nextnode.x=thisnode.x+dir[i][0]; 121 nextnode.y=thisnode.y+dir[i][1]; 122 if(legal(nextnode.x,nextnode.y)&&map[nextnode.x][nextnode.y]=='.'&&vis[nextnode.x][nextnode.y]==0){ 123 vis[nextnode.x][nextnode.y]=1; 124 nextnode.step=thisnode.step+1; 125 how_many_steps_F[nextnode.x][nextnode.y]=nextnode.step; 126 q.push(nextnode); 127 } 128 } 129 } 130 }
这样严谨的开数组,比无脑开数组的好处就是知道哪个地方开小了会产生什么问题,更加透彻理解代码逻辑,为了以后可以无脑开数组
就像学数学是为了,不是买菜用不上就不学,相反数学学好了为了买菜不用数学,可以不用有顾虑的花销,不用计算手头还有多少钱
记录坎坷:
###:写着火地图更新的时候,注意别把所有的 '.' 一次全弄成 'F’ 了
###:突然想了下BFS时间复杂度,怎么感觉是m*n呢?先不考虑复杂度
###:除了思考之前BUPT导师批改初试手写代码、吴师兄看代码,还有大型工程项目是怎么修改的,怎么让不同人接手维护的,我自己代码一星期后都看不懂,也不咋好加东西,只有趁热乎才能修改
###:最大值先用memset 1来弄
###:洛谷讨论区给出的几个样例
###:麻痹的之前跟那些把Ctrl+C,Ctrl+S快捷键记录到便利贴上,放电脑屏幕前的傻逼女测试一起干银行外包测试,真他妈耻辱,艹,老子离职学开发,19~23年的4年梦魇我会夺回来,28岁才工作一年,哎
###:本来想看看讨论区那些TLE的帮他们改改,结果发现真看不懂
###:这题好小众
###:走了这么多弯路,不希望别人再走我这样坎坷的路,如果有看不懂的可以留言,看到后会弄个视频讲解,现场写