算法筆記_107:藍橋杯練習 算法提高 學霸的迷宮(Java)


目錄

1 問題描述

2 解決方案

 


1 問題描述

問題描述
  學霸搶走了大家的作業,班長為了幫同學們找回作業,決定去找學霸決斗。但學霸為了不要別人打擾,住在一個城堡里,城堡外面是一個二維的格子迷宮,要進城堡必須得先通過迷宮。因為班長還有妹子要陪,磨刀不誤砍柴功,他為了節約時間,從線人那里搞到了迷宮的地圖,准備提前計算最短的路線。可是他現在正向妹子解釋這件事情,於是就委托你幫他找一條最短的路線。
輸入格式
  第一行兩個整數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。

 


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);
    }
}

 

 

 

 

參考資料:

1.藍橋杯 算法提高 學霸的迷宮

2.藍橋杯練習系統試題集 算法提高 ADV-147 學霸的迷宮

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM