1. 程式人生 > >adv147(藍橋杯) 學霸的迷宮 bfs

adv147(藍橋杯) 學霸的迷宮 bfs

pop air fin pair 前端 提前 cal 路徑 emp

問題描述   學霸搶走了大家的作業,班長為了幫同學們找回作業,決定去找學霸決鬥。但學霸為了不要別人打擾,住在一個城堡裏,城堡外面是一個二維的格子迷宮,要進城堡必須得先通過迷宮。因為班長還有妹子要陪,磨刀不誤砍柴功,他為了節約時間,從線人那裏搞到了迷宮的地圖,準備提前計算最短的路線。可是他現在正向妹子解釋這件事情,於是就委托你幫他找一條最短的路線。 輸入格式   第一行兩個整數n, m,為迷宮的長寬。
  接下來n行,每行m個數,數之間沒有間隔,為0或1中的一個。0表示這個格子可以通過,1表示不可以。假設你現在已經在迷宮坐標(1,1)的地方,即左上角,迷宮的出口在(n,m)。每次移動時只能向上下左右4個方向移動到另外一個可以通過的格子裏,每次移動算一步。數據保證(1,1),(n,m)可以通過。 輸出格式   第一行一個數為需要的最少步數K。
  第二行K個字符,每個字符∈{U,D,L,R},分別表示上下左右。如果有多條長度相同的最短路徑,選擇在此表示方法下字典序最小的一個。 樣例輸入 Input Sample 1:
3 3
001
100
110

Input Sample 2:
3 3
000
000
000 樣例輸出 Output Sample 1:
4
RDRD

Output Sample 2:
4
DDRR 數據規模和約定   有20%的數據滿足:1<=n,m<=10
  有50%的數據滿足:1<=n,m<=50
  有100%的數據滿足:1<=n,m<=500。
#include<iostream>
#include
<queue> #include<stack> #include<cstdio> #include<cstring> using namespace std; #define MAX 500 + 5 //#define LOCAL typedef pair<int, int> P; int n, m; char a[MAX][MAX]; int d[MAX][MAX]; struct father{ int x; int y; char c; }f[MAX][MAX]; stack <char> fa;
int dx[4] = {1, 0, 0, -1}, dy[4] = {0, -1, 1, 0}; //考慮字典序輸出問題 int bfs() { queue<P> que; //將起點加入隊列,並將這一點的位置設置為0 que.push(P(1, 1)); d[1][1] = 0; //不斷循環直到隊列為0 while(que.size()) { //從隊列前端取出元素 P p = que.front(); que.pop(); //如果取出的是終點,搜索結束 if(p.first == n && p.second == m) break
; //四個方向的循環 for(int i = 0; i < 4; i++) { //移動之後的位置標記為 nx, ny int nx = p.first + dx[i], ny = p.second + dy[i]; //判斷是否可以訪問以及是否訪問過 if(1 <= nx && nx <= n && 1 <= ny && ny <= m && a[nx][ny] == 0 && d[nx][ny] == -1) { que.push(P(nx, ny)); d[nx][ny] = d[p.first][p.second] + 1; f[nx][ny].x = p.first; f[nx][ny].y = p.second; switch (i) { case 0: f[nx][ny].c = D;break; case 1: f[nx][ny].c = L;break; case 2: f[nx][ny].c = R;break; case 3: f[nx][ny].c = U;break; } } } } return d[n][m]; } int main() { #ifdef LOCAL freopen("adv_147.txt", "r", stdin); #endif memset(d, -1, sizeof(d)); //char temp; cin >> n >> m; //輸入數據 for(int i = 1; i <= n; i++) cin >> a[i] + 1; int res = bfs(); cout << res << endl;
  由於每個fa元素僅記錄其父節點位置,所以考慮用棧來實現輸出路線,其實用遞歸也可以。
int f_x, f_y; father temp = f[n][m]; for(int j = res; j > 0; j--) { fa.push(temp.c); f_x = temp.x; f_y = temp.y; temp = f[f_x][f_y]; } for(int k = 0; k < res; k++) { cout << fa.top(); fa.pop(); } cout << endl; return 0; }

註意點: 註意到如果有多條長度相同的最短路徑,選擇在此表示方法下字典序最小的一個所以技巧是在準備遍歷順序是就考慮字典序(D, L, R, U),因為BFS的特性是對已掃描過的點不會進行二次掃描。

adv147(藍橋杯) 學霸的迷宮 bfs