藍橋杯訓練: 學霸的迷宮(bfs)
阿新 • • 發佈:2019-01-27
一道普通的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;
}
}