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

藍橋杯訓練: 學霸的迷宮(bfs)

一道普通的bfs+路徑儲存題,做了大半天,很多細節沒注意,除錯了好久,都是因為平時太好高騖遠不肯動手寫的後果,寫下來當作教訓!
問題描述
  學霸搶走了大家的作業,班長為了幫同學們找回作業,決定去找學霸決鬥。但學霸為了不要別人打擾,住在一個城堡裡,城堡外面是一個二維的格子迷宮,要進城堡必須得先通過迷宮。因為班長還有妹子要陪,磨刀不誤砍柴功,他為了節約時間,從線人那裡搞到了迷宮的地圖,準備提前計算最短的路線。可是他現在正向妹子解釋這件事情,於是就委託你幫他找一條最短的路線。
輸入格式
  第一行兩個整數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。

/* 
注意點:
1.普通的bfs題
2.因為要輸出路徑,通過多開一個數組來儲存前驅結點到達當前結點的方向,通過方向可以找到前驅結點,輸出的時候可以遞迴呼叫,程式碼簡潔。
3.因為要保證字元字典序最小,所以探索的時候要保持D,R,L,U四個方向的先後順序,這樣就能保證在相同步數的不同路徑下,最先到達的路徑字典序最小(不太理解的可以畫個圖嘗試)
*/
import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); char[][] map = new char[n][]; in
.nextLine(); for (int i = 0; i < n; i++) map[i] = in.nextLine().toCharArray(); bfs(0, 0, map, n - 1, m - 1); } private static void bfs(int n, int m, char[][] map, int targetx, int targety) { Queue<Point> queue = new LinkedList<Point>(); int[][][] p = new int[targetx + 1][targety + 1][3];// p為儲存前一節點到當前結點的方向 int[][] dir = new int[][] { { 1, 0, 0 }, { 0, -1, 1 }, { 0, 1, 2 }, { -1, 0, 3 } };// 方向是一個2維陣列,其中元素的前兩位是方向,第三位對應字元 char[] c = new char[] { 'D', 'L', 'R', 'U' };// 因為要按字典序輸出,所以要保持D,L,R,U的順序 queue.add(new Point(n, m, 0)); map[n][m] = '1'; while (!queue.isEmpty()) { Point point = queue.poll(); if (point.x == targetx && point.y == targety) { System.out.println(point.step); printPath(p, point.x, point.y, c); } for (int i = 0; i < 4; i++) { int x = point.x + dir[i][0]; int y = point.y + dir[i][1]; int step = point.step + 1; if ((x >= 0 && x < targetx + 1) && (y >= 0 && y < targety + 1) && map[x][y] != '1') { map[x][y] = '1'; queue.add(new Point(x, y, step)); p[x][y] = dir[i]; // 儲存前驅結點 } } } } // 通過遞迴的方法列印路徑 private static void printPath(int[][][] p, int x, int y, char[] c) { if (x == 0 && y == 0) return; printPath(p, x - p[x][y][0], y - p[x][y][1], c); System.out.print(c[p[x][y][2]]); } } class Point { int x; int y; int step; Point(int x, int y, int step) { this.x = x; this.y = y; this.step = step; } }