1. 程式人生 > 其它 >2019第十屆藍橋杯B組C++省賽E題 迷宮

2019第十屆藍橋杯B組C++省賽E題 迷宮

題目連結 https://www.lanqiao.cn/problems/602/learning/

廣度優先搜尋最短路徑輸出表示

(唉。。。。。。。。。。。)


 

此題有三種方法:①搜兩遍,第一遍算最短路徑,第二遍輸出路徑(也是本篇部落格使用的方法);②搜一遍,一邊搜一遍記錄路徑(我不會);③搜一遍,用二維陣列儲存四個值(我更不會)。

(詳情見https://blog.csdn.net/weixin_44965308/article/details/104928695


 

先說一下我錯誤的思路:先正著從起點開始搜一遍,求出每個點到起點的最短距離,再正著搜一遍,從起點往終點走,找比上一個大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)。

好吧......我不能理解為什麼變成是“從(0,0)到(29,49)字典序最小的最短路徑”.....


 

放一個倒搜的半懂不懂的程式碼:

 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,等問過老師再來更新吧。