目錄
1 問題描述
問題描述
學霸搶走了大家的作業,班長為了幫同學們找回作業,決定去找學霸決斗。但學霸為了不要別人打擾,住在一個城堡里,城堡外面是一個二維的格子迷宮,要進城堡必須得先通過迷宮。因為班長還有妹子要陪,磨刀不誤砍柴功,他為了節約時間,從線人那里搞到了迷宮的地圖,准備提前計算最短的路線。可是他現在正向妹子解釋這件事情,於是就委托你幫他找一條最短的路線。
輸入格式
第一行兩個整數n, m,為迷宮的長寬。
接下來n行,每行m個數,數之間沒有間隔,為0或1中的一個。0表示這個格子可以通過,1表示不可以。假設你現在已經在迷宮坐標(1,1)的地方,即左上角,迷宮的出口在(n,m)。每次移動時只能向上下左右4個方向移動到另外一個可以通過的格子里,每次移動算一步。數據保證(1,1),(n,m)可以通過。
接下來n行,每行m個數,數之間沒有間隔,為0或1中的一個。0表示這個格子可以通過,1表示不可以。假設你現在已經在迷宮坐標(1,1)的地方,即左上角,迷宮的出口在(n,m)。每次移動時只能向上下左右4個方向移動到另外一個可以通過的格子里,每次移動算一步。數據保證(1,1),(n,m)可以通過。
輸出格式
第一行一個數為需要的最少步數K。
第二行K個字符,每個字符∈{U,D,L,R},分別表示上下左右。如果有多條長度相同的最短路徑,選擇在此表示方法下字典序最小的一個。
第二行K個字符,每個字符∈{U,D,L,R},分別表示上下左右。如果有多條長度相同的最短路徑,選擇在此表示方法下字典序最小的一個。
樣例輸入
Input Sample 1:
3 3
001
100
110
Input Sample 2:
3 3
000
000
000
3 3
001
100
110
Input Sample 2:
3 3
000
000
000
樣例輸出
Output Sample 1:
4
RDRD
Output Sample 2:
4
DDRR
4
RDRD
Output Sample 2:
4
DDRR
數據規模和約定
有20%的數據滿足:1<=n,m<=10
有50%的數據滿足:1<=n,m<=50
有100%的數據滿足:1<=n,m<=500。
有50%的數據滿足:1<=n,m<=50
有100%的數據滿足:1<=n,m<=500。
2 解決方案
此題主要考查bfs遍歷的具體應用。
具體思想可以參考代碼注釋哦。
具體代碼如下:
import java.util.ArrayList; import java.util.Scanner; public class Main { public final static int[][] move = {{-1, 0},{1,0},{0,-1},{0,1}};//分別表示向上、下、左、右移動一步 public final static String[] onePath = {"U","D","L","R"};//分別表示向上、下、左、右行走 static class point { //內部類,用於表示當前行走到達點信息 public int x; //當前到達位置橫坐標 public int y; //當前到達位置縱坐標 public int step; //行走到當前頂點所用總步數 public String path; //行走到當前頂點的具體路徑 point(int x, int y, int step, String path) { this.x = x; this.y = y; this.step = step; this.path = path; } } //判斷當前位置是否是可行走的位置,如不能返回false,否則返回true public boolean check(int[][] matrix, point a) { int n = matrix.length - 1, m = matrix[0].length - 1; if(a.x < 1 || a.x > n || a.y < 1 || a.y > m || matrix[a.x][a.y] == 1) return false; return true; } //依據字典序{D,L,R,U},比較字符串A和B的大小,如果A > B返回true,否則返回false(PS:兩者字符個數相同) public boolean judge(String A, String B) { char[] arrayA = A.toCharArray(); char[] arrayB = B.toCharArray(); for(int i = 0, len = A.length();i < len;i++) { if(arrayA[i] < arrayB[i]) return false; } return true; } //把輸入數據,變換為矩陣 public int[][] getMatrix(String[] A, int m) { int[][] matrix = new int[A.length + 1][m + 1]; for(int i = 0;i < A.length;i++) { char[] arrayA = A[i].toCharArray(); for(int j = 0;j < m;j++) matrix[i + 1][j + 1] = arrayA[j] - '0'; } return matrix; } public void bfs(String[] A, int m) { int[][] matrix = getMatrix(A, m); ArrayList<point> list = new ArrayList<point>(); list.add(new point(1,1,0,"")); //表示從頂點(1,1)出發 int minStep = Integer.MAX_VALUE; //用於記錄到達最終頂點所需最少步數 String minPath = ""; //用於記錄到達最終頂點路徑的最小字典序序列 while(list.size() != 0) { point begin = list.get(0); //獲取鏈表第一個頂點,開始進行bfs遍歷 list.remove(0); //刪除進行遍歷的起始點 if(begin.x == matrix.length - 1 && begin.y == matrix[0].length - 1) { //當該頂點為終點時 if(minStep > begin.step) { minStep = begin.step; minPath = begin.path; } else if(minStep == begin.step) { if(judge(minPath, begin.path)) //當minPath字典序大於begin.step時 minPath = begin.path; } continue; //此處已經是終點,不需要進行下面bfs遍歷 } for(int i = 0;i < 4;i++) { //如果未達到最終頂點(n, m),進行bfs遍歷(分別向上、下、左、右移動) int x = begin.x + move[i][0]; int y = begin.y + move[i][1]; int step = begin.step + 1; String path = begin.path + onePath[i] ; point temp = new point(x, y, step, path); if(check(matrix, temp)) { //當頂點temp是可到達的頂點時 list.add(temp); matrix[x][y] = 1; //到達該頂點后,標記該頂點不可到達,此處奧秘是大大減少了檢索次數(如果換成其父母頂點不可到達,則會運行超時) } } } //輸出最終結果 System.out.println(minStep+"\n"+minPath); return; } public static void main(String[] args) { Main test = new Main(); Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); in.nextLine(); //此處特別注意,輸入完整數,下面接着輸出字符串,此處處理換行操作 String[] A = new String[n]; for(int i = 0;i < n;i++) A[i] = in.nextLine(); test.bfs(A, m); } }
參考資料:
2.藍橋杯練習系統試題集 算法提高 ADV-147 學霸的迷宮