2019第十届蓝桥杯B组C++省赛E题 迷宫
题目链接 https://www.lanqiao.cn/problems/602/learning/
bfs最短路径输出表示
此题有五种方法orz...(唉。。。。。。。。。。。),总结在这里。这里用的第一种方法(见下面的思路)。
先说一下我错误的思路:先正着从起点开始搜一遍,求出每个点到起点的最短距离,再正着搜一遍,从起点往终点走,找比上一个大1的点,找到后记录路径,最后输出路径。
是这样的,这样是错误的,至于他为什么错,很难过,搞了两天也没搞懂。(下面有说)
接下来说一下正确的思路:先倒着从终点开始搜一遍,求出每个点到终点的最短距离,再正着搜一遍,从起点往终点走,找比上一个小1的点,找到后记录路径,最后输出路径。
为什么第一遍不能正着搜?有个dalao的解释是这样的:
回溯的时候有这种请况在dis[x][y]=147的时候下一步有两个点可以走都是最短的。因为迷宫里最短路径并非唯一,BFS可以求的最短路径没错,但得到的与题目要求的字典序最小可能不一样。有人说,按DLRU顺序走就可以了,但是,是开始标记dis数组时按着这顺序,还是回溯时按这个顺序呢?
答案是如果开始标记dis数组时是倒着搜时,然后回溯时按这个顺序是对的,但如果开始时正着搜的,那么回溯时就不能按这个顺序了,因为这样得到的路径是从(29,49)到(0,0)字典序最小的最短路径而不是从(0,0)到(29,49)字典序最小的最短路径。(原文链接https://blog.csdn.net/qq_40691051/article/details/102467168)。
好吧......我不能理解为什么变成是“从(29,49)到(0,0)字典序最小的最短路径”.....
放一个倒搜的模仿的dalao的半懂不懂的代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 char a[40][60];//存图 4 int dis[40][60];//存放各点到终点的距离,亦有类似于标记的作用 5 int dx[4]={1,0,0,-1};//字典序直接把方向数组处理好 6 int dy[4]={0,-1,1,0}; 7 char ch[4]={'D','L','R','U'}; 8 string st;//存答案 9 struct node 10 { 11 int x; 12 int y; 13 }; 14 bool check(int x, int y) 15 { 16 return x>0&&y>0&&x<=30&&y<=50&&a[x][y]=='0'&&dis[x][y]==-1; 17 } 18 void bfs(int bx,int by) 19 {//第一遍搜索求出各点到终点的最短距离 20 memset(dis,-1,sizeof(dis)); 21 queue<node>q; 22 node start,next; 23 start.x=bx; 24 start.y=by; 25 q.push(start); 26 dis[30][50]=0; 27 while(!q.empty()) 28 { 29 start=q.front(); 30 q.pop(); 31 for(register int i=0;i<4;i++) 32 { 33 next.x=start.x+dx[i]; 34 next.y=start.y+dy[i]; 35 if(check(next.x,next.y)) 36 { 37 dis[next.x][next.y]=dis[start.x][start.y]+1; 38 q.push(next); 39 } 40 } 41 } 42 } 43 int main() 44 { 45 for(int i=1;i<=30;i++) 46 for(int j=1;j<=50;j++) 47 cin>>a[i][j]; 48 bfs(30,50); 49 int x=1,y=1;//从起点开始遍历 50 while(x!=30||y!=50) 51 { 52 for(int i=0;i<4;i++) 53 { 54 int newx=x+dx[i]; 55 int newy=y+dy[i]; 56 if(newx>0&&newx<=30&&newy>0&&newy<=50&&a[newx][newy]=='0'&&dis[newx][newy]==dis[x][y]-1) 57 { 58 x=newx; y=newy; 59 st+=ch[i]; 60 break; 61 } 62 } 63 } 64 cout<<st<<endl; 65 return 0; 66 }
这是我错误思路的代码:(不重要!划掉!)
(第26、48、56行不同)
1 #include <bits/stdc++.h> 2 using namespace std; 3 char a[40][60];//存图 4 int dis[40][60];//存放各点到终点的距离,亦有类似于标记的作用 5 int dx[4]={-1,0,0,1};//字典序直接把方向数组处理好 6 int dy[4]={0,1,-1,0}; 7 char ch[4]={'D','L','R','U'}; 8 string st;//存答案 9 struct node 10 { 11 int x; 12 int y; 13 }; 14 bool check(int x, int y) 15 { 16 return x>0&&y>0&&x<=30&&y<=50&&a[x][y]=='0'&&dis[x][y]==-1; 17 } 18 void bfs(int bx,int by) 19 {//第一遍搜索求出各点到终点的最短距离 20 memset(dis,-1,sizeof(dis)); 21 queue<node>q; 22 node start,next; 23 start.x=bx; 24 start.y=by; 25 q.push(start); 26 dis[1][1]=0; 27 while(!q.empty()) 28 { 29 start=q.front(); 30 q.pop(); 31 for(register int i=0;i<4;i++) 32 { 33 next.x=start.x+dx[i]; 34 next.y=start.y+dy[i]; 35 if(check(next.x,next.y)) 36 { 37 dis[next.x][next.y]=dis[start.x][start.y]+1; 38 q.push(next); 39 } 40 } 41 } 42 } 43 int main() 44 { 45 for(int i=1;i<=30;i++) 46 for(int j=1;j<=50;j++) 47 cin>>a[i][j]; 48 bfs(1,1); 49 int x=1,y=1;//从起点开始遍历 50 while(x!=30||y!=50) 51 { 52 for(int i=0;i<4;i++) 53 { 54 int newx=x+dx[i]; 55 int newy=y+dy[i]; 56 if(newx>0&&newx<=30&&newy>0&&newy<=50&&a[newx][newy]=='0'&&dis[newx][newy]==dis[x][y]+1) 57 { 58 x=newx; y=newy; 59 st+=ch[i]; 60 break; 61 } 62 } 63 } 64 cout<<st<<endl; 65 return 0; 66 }
好心累,dalao的讲解看不懂,lqs和cjh讲的也不理解。。。。。。5555555,等问过老师再来更新吧。