列表

详情


LCP 31. 变换的迷宫

某解密游戏中,有一个 N*M 的迷宫,迷宫地形会随时间变化而改变,迷宫出口一直位于 (n-1,m-1) 位置。迷宫变化规律记录于 maze 中,maze[i] 表示 i 时刻迷宫的地形状态,"." 表示可通行空地,"#" 表示陷阱。

地形图初始状态记作 maze[0],此时小力位于起点 (0,0)。此后每一时刻可选择往上、下、左、右其一方向走一步,或者停留在原地。

小力背包有以下两个魔法卷轴(卷轴使用一次后消失):

请判断在迷宫变化结束前(含最后时刻),小力能否在不经过任意陷阱的情况下到达迷宫出口呢?

注意: 输入数据保证起点和终点在所有时刻均为空地。

示例 1:

输入:maze = [[".#.","#.."],["...",".#."],[".##",".#."],["..#",".#."]]

输出:true

解释: maze.gif

示例 2:

输入:maze = [[".#.","..."],["...","..."]]

输出:false

解释:由于时间不够,小力无法到达终点逃出迷宫。

示例 3:

输入:maze = [["...","...","..."],[".##","###","##."],[".##","###","##."],[".##","###","##."],[".##","###","##."],[".##","###","##."],[".##","###","##."]]

输出:false

解释:由于道路不通,小力无法到达终点逃出迷宫。

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: bool escapeMaze(vector<vector<string>>& maze) { } };

golang 解法, 执行用时: 36 ms, 内存消耗: 7.2 MB, 提交时间: 2023-10-27 22:30:52

var dir4 = []struct{ x, y int }{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}

func escapeMaze(g [][]string) bool {
	k, n, m := len(g), len(g[0]), len(g[0][0])
	vis := make([][][][6]bool, k)
	for i := range vis {
		vis[i] = make([][][6]bool, n)
		for j := range vis[i] {
			vis[i][j] = make([][6]bool, m)
		}
	}
	// s 的最低位:是否使用了临时消除术
	// s 的其余位:0-未使用永久消除术,1-当前正位于永久消除的位置,2-已使用永久消除术
	var f func(t, x, y, s int) bool
	f = func(t, x, y, s int) bool {
		if x < 0 || x >= n || y < 0 || y >= m || t+n-1-x+m-1-y >= k || vis[t][x][y][s] {
			return false
		}
		if x == n-1 && y == m-1 {
			return true
		}
		vis[t][x][y][s] = true
		if s>>1 == 1 {
			for _, d := range dir4 {
				if f(t+1, x+d.x, y+d.y, s^6) { // 跳出永久消除的位置
					return true
				}
			}
			return f(t+1, x, y, s)
		}
		if s>>1 == 0 && g[t][x][y] == '#' && f(t, x, y, s|2) { // 尝试使用永久消除术
			return true
		}
		// 使用永久消除术已无法走到终点,遇到障碍只能使用临时消除术
		if g[t][x][y] == '#' {
			if s&1 == 1 {
				return false
			}
			s |= 1
		}
		for _, d := range dir4 {
			if f(t+1, x+d.x, y+d.y, s) {
				return true
			}
		}
		return f(t+1, x, y, s)
	}
	return f(0, 0, 0, 0)
}

java 解法, 执行用时: 43 ms, 内存消耗: 44.1 MB, 提交时间: 2023-10-27 22:30:29

class Solution {

    int[][][] dp;
    int[][] preUse;
    int m,n,t;

    public boolean escapeMaze(List<List<String>> maze) {
        m = maze.get(0).size();
        n = maze.get(0).get(0).length();
        t = maze.size();
        dp = new int[t][m][n];
        preUse = new int[m][n];
        
        //其他位置转移到此 状态转移表
        int[] next = {0,0,0,1,2,4};
        //上次在当前位置使用卷轴 状态转移表
        int[] preS = {0,0,2,3,3,-1};

        for(int k = 0; k<t ;k++) {
            //初始化起点状态
            dp[k][0][0]=5;
        }
        for (int ct = 1; ct < t; ct++) {
            for(int i=0;i<m;i++) {
                for(int j=0;j<n;j++) {
                    if(i==0 && j==0) continue;
                    int pre = calMax(ct-1, i, j);
                    if (maze.get(ct).get(i).charAt(j) != '.') {
                        dp[ct][i][j] = Math.max(next[pre], preS[preUse[i][j]]);
                        preUse[i][j] = dp[ct][i][j];
                    } else {
                        dp[ct][i][j] = pre;
                    }
                }
            }
            if(dp[ct][m-1][n-1] > 0) return true;
        }

        return false;
    }

    int calMax(int t,int i, int j) {
        int max = dp[t][i][j];
        if (i>0) max = Math.max(max, dp[t][i-1][j]);
        if (j>0) max = Math.max(max, dp[t][i][j-1]);
        if (i<m-1) max = Math.max(max, dp[t][i+1][j]);
        if (j<n-1) max = Math.max(max, dp[t][i][j+1]);
        return max;
    }

}

cpp 解法, 执行用时: 544 ms, 内存消耗: 30.8 MB, 提交时间: 2023-10-27 22:30:08

int dp[105][55][55][5];
int can[55][55][2];
class Solution {
public:
    bool escapeMaze(vector<vector<string>>& maze) {
        int T = maze.size(), m = maze[0].size(), n = maze[0][0].size();
        
        for(int t = 0; t < T; ++t)
            for(int i = 0; i < m; ++i)
                for(int j = 0; j < n; ++j)
                    for(int k = 0; k < 4; ++k) 
                        dp[t][i][j][k] = 0;
        
        for(int i = 0; i < m; ++i)
            for(int j = 0; j < n;++j)
                can[i][j][0] = can[i][j][1] = 0;
        
        for(int t = 0; t < T; ++t)
            for(int k = 0; k < 4; ++k)
                dp[t][m-1][n-1][k] = 1;
        
        can[m-1][n-1][0] = can[m-1][n-1][1] = 1;

        int dx[] = {1, -1, 0, 0, 0}, dy[] = {0, 0, 1, -1, 0};
        for(int t = T-2; t >= 0; --t) {
            for(int i = 0; i < m; ++i) {
                for(int j = 0; j < n; ++j) {
                    for(int k = 0; k < 4; ++k) {
                        int u1 = k & 1, u2 = k & 2;
                        for(int d = 0; d < 5; ++d) {
                            int ii = i + dx[d], jj = j + dy[d];
                            if(ii >= 0 && ii < m && jj >= 0 && jj < n) {
                                if(maze[t+1][ii][jj] == '.') {
                                    dp[t][i][j][k] |= dp[t + 1][ii][jj][k];
                                } else {
                                    if(!u1) dp[t][i][j][k] |= dp[t + 1][ii][jj][k | 1];
                                    if(!u2) dp[t][i][j][k] |= can[ii][jj][u1];
                                }
                            }
                        }
                    }
                }
            }
            for(int i = 0; i < m; ++i) {
                for(int j = 0; j < n; ++j) {
                    can[i][j][0] |= dp[t][i][j][2];
                    can[i][j][1] |= dp[t][i][j][3];
                }
            }
        }
        return dp[0][0][0][0]? true : false;
    }
};

cpp 解法, 执行用时: 84 ms, 内存消耗: 26.6 MB, 提交时间: 2023-10-27 22:29:40

class Solution {
public:
    int dx[5] = {0, 1, 0,-1,0};
    int dy[5] = {1, 0,-1,0,0};
    int n; //n行m列
    int m;
    int max_step; //最大步数
    bool visited[55][55][105][2][2] = {false};  // 记忆化搜索,是否已访问过
    bool dfs(int x, int y, int step, bool magic1, bool magic2, const vector<vector<string>>& maze){
        if(visited[x][y][step][magic1][magic2] == true) return false;  // 历史已访问过,相同case已不可能
        visited[x][y][step][magic1][magic2] = true;
        if(x == n-1 && y == m-1) return true;//到达终点
        if(step == max_step) return false;//最大步数都用完了还没走到终点 GG
        if(max_step - step < n-1-x + m-1-y) return false; // 不可能再走到终点了 剪枝
        for(int i=0; i<5; i++){ //尝试每一种next_state
            int fx = x + dx[i];
            int fy = y + dy[i];
            if(fx>=0 && fx<n && fy>=0 && fy<m){ //如果在地图内
                if(maze[step+1][fx][fy] == '.'){ //如果是空地可以直接踩过去
                    if(dfs(fx, fy, step+1, magic1, magic2, maze)) return true;
                }
                else{ //如果是陷阱则需要魔法才能踩过去
                    if(magic1 == false){ //使用临时魔法,在下一时刻踩过去
                        if( dfs(fx, fy, step+1, true, magic2, maze)) return true;
                    }
                    if(magic2 == false){//使用永久魔法,在下一时刻至最后一个时刻,选择一个时刻踩过去
                        for(int i=step+1; i<=max_step; i++){
                            if(dfs(fx, fy, i, magic1, true, maze)) return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    bool escapeMaze(vector<vector<string>>& maze) {
        n = maze[0].size();
        m = maze[0][0].size();
        max_step = maze.size() - 1;
        return dfs(0, 0, 0, false, false, maze);
    }
};

python3 解法, 执行用时: 620 ms, 内存消耗: 45.1 MB, 提交时间: 2023-10-27 22:29:25

class Solution:
    def escapeMaze(self, maze: List[List[str]]) -> bool:
        max_dep, n, m = len(maze), len(maze[0]), len(maze[0][0])
        # 下一点移动方式
        dirs = [(1, 0), (0, 1), (-1, 0), (0, -1), (0, 0)]
        # 记忆化搜索(为python缓存机制)
        @lru_cache(None)
        def dfs(x, y, dep, magic_a, magic_b):
            # print(x, y, dep, magic_a, magic_b)
            if x == n - 1 and y == m - 1:
                return True
            if dep + 1 == max_dep:
                return False
            # 剪枝
            if n - 1 - x + m - 1 - y > max_dep - dep - 1:
                return False
            for i, j in dirs:
                xx, yy = x + i, y + j
                if xx < 0 or xx == n or yy < 0 or yy == m:
                    continue
                # 下一点为平地
                if maze[dep + 1][xx][yy] == '.':
                    if dfs(xx, yy, dep + 1, magic_a, magic_b):
                        return True
                # 下一点需要使用卷轴
                else:
                    if not magic_a:
                        # 临时卷轴
                        if dfs(xx, yy, dep + 1, True, magic_b):
                            return True
                    if not magic_b:
                        # 用永久卷轴保持不动
                        for next_dep in range(dep + 1, max_dep):
                            if dfs(xx, yy, next_dep, magic_a, True):
                                return True
            return False
        return dfs(0, 0, 0, False, False)

上一题