滴滴出行之地下迷宮

題目描述

小青蛙有一天不小心落入了一個地下迷宮,小青蛙希望用自己僅剩的體力值P跳出這個地下迷宮。爲了讓問題簡單,假設這是一個n*m的格子迷宮,迷宮每個位置爲0或者1,0代表這個位置有障礙物,小青蛙達到不了這個位置;1代表小青蛙可以達到的位置。小青蛙初始在(0,0)位置,地下迷宮的出口在(0,m-1)(保證這兩個位置都是1,並且保證一定有起點到終點可達的路徑),小青蛙在迷宮中水平移動一個單位距離需要消耗1點體力值,向上爬一個單位距離需要消耗3個單位的體力值,向下移動不消耗體力值,當小青蛙的體力值等於0的時候還沒有到達出口,小青蛙將無法逃離迷宮。現在需要你幫助小青蛙計算出能否用僅剩的體力值跳出迷宮(即達到(0,m-1)位置)。

輸入描述:

輸入包括n+1行:
第一行爲三個整數n,m(3 <= m,n <= 10),P(1 <= P <= 100)
接下來的n行:
每行m個0或者1,以空格分隔

輸出描述:

如果能逃離迷宮,則輸出一行體力消耗最小的路徑,輸出格式見樣例所示;如果不能逃離迷宮,則輸出”Can not escape!”。 測試數據保證答案唯一

示例

輸入
4 4 10 1 0 0 1 1 1 0 1 0 1 1 1 0 0 1 1
輸出
[0,0],[1,0],[1,1],[2,1],[2,2],[2,3],[1,3],[0,3]
從題目上看這是一道DFS的題,遞歸+回溯就可以解決這個問題了。
窮舉所有的路徑找到消耗最小的那個路徑。
畫不多說,看下面的代碼:

import java.util.LinkedList;
import java.util.Scanner;
public class UndergroundMaze {
    static int[][] map; // 地圖
    static int mark[][];    // 標記該點是否走過,其中1爲走過,0爲沒走過
    static int n, m;    // 地圖大小
    static int P;       // 體力值
    static int hasenergy = 0;    // 找到路徑是剩餘的體力值
    static LinkedList<String> temp = new LinkedList<>();    // 暫存路徑
    static LinkedList<String> path;     // 最終的路徑
    static boolean isFind = false;      // 是否找到
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);    // 獲取輸入流
        // 輸入
        n = sc.nextInt();
        m = sc.nextInt();
        P = sc.nextInt();
        map = new int[n][m];
        mark = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                map[i][j] = sc.nextInt();
            }
        }
        // DFS找路徑
        DFS(0, 0, P);
        if (isFind) {   // 找到了
            for (int i = 0; i < path.size(); i++) {
                if (i == path.size() - 1) {
                    System.out.print(path.get(i));
                    continue;
                }
                System.out.print(path.get(i) + ",");
            }
        } else {    // 沒找到
            System.out.println("Can not escape!");
        }
    }

    public static void DFS (int x, int y , int enery) {
        if (x >= 0 && x < n && y >= 0 && y < m && map[x][y] == 1 &&
                mark[x][y] == 0 &&enery >= 0) { // 滿足座標合法,能走,之前沒走過,有體力值
            temp.add("[" + x + "," + y + "]");  // 加入暫存的路徑
            mark[x][y] = 1;     // 標記該點走過
            if (x == 0 && y == m - 1) { // 找到出口
                if (enery >= hasenergy) {   // 可能會有多條路徑,比較找到體力剩餘最多的
                    hasenergy = enery;
                    path = new LinkedList<>(temp);  // 最終路徑
                }
                // 回溯,遍歷所有可能的路徑,找到一條使用體力最少的路徑。
                mark[x][y] = 0;
                temp.removeLast();
                isFind = true;
                return;
            } else {
                // 遞歸
                DFS(x + 1, y, enery);
                DFS(x - 1, y, enery - 3);
                DFS(x, y + 1, enery - 1);
                DFS(x, y - 1, enery - 1);
                // 回溯
                mark[x][y] = 0;
                temp.removeLast();
            }
        } else
            return;
    }
}
点赞