题目:原题链接(困难)

标签:动态规划、广度优先搜索

解法 时间复杂度 空间复杂度 执行用时
Ans 1 (Python) O ( N × M × T ) O(N×M×T) O(N×M×T) O ( N × M × T ) O(N×M×T) O(N×M×T) 3264ms (27.32%)
Ans 2 (Python)
Ans 3 (Python)

解法一:

class Solution:
    def escapeMaze(self, maze: List[List[str]]) -> bool:
        time = len(maze)  # 总时长
        n, m = len(maze[0]), len(maze[0][0])  # 迷宫长宽

        # 当前时间状态矩阵:dp[i][j][k][l]  当前时间到达第(i,j)个位置的迷宫、k=True/False使用了临时消除术、的可选永久消除术使用位置列表
        dp1 = [[[set() for _ in range(2)] for _ in range(m)] for _ in range(n)]
        dp1[0][0][False] = None  # None表示存在尚未使用永久消除术的方法

        # 广度优先搜索方式状态转移:纵坐标、横坐标、是否使用临时消除术
        queue1 = {(0, 0, False)}

        t = 0  # 当前时间变量
        while t < time - 1:
            # 下一个时间结点的状态矩阵
            dp2 = [[[set() for _ in range(2)] for _ in range(m)] for _ in range(n)]
            queue2 = set()

            for i1, j1, use in queue1:  # 提取当前位置

                # 计算当前剩余距离
                d = (n - i1 - 1) + (m - j1 - 1)

                # 如果已经到达终点,则返回True
                if d == 0:
                    return True

                # 计算剩余时间(还能移动的次数)
                s = time - t - 1

                # 如果剩余时间不足,则直接跳过当前情况
                if s - d < 0:
                    continue

                # 生成所有可能的下一步的选择
                maybe_next = []
                if i1 < n - 1:  # 向下走
                    maybe_next.append((i1 + 1, j1))
                if j1 < m - 1:  # 向右走
                    maybe_next.append((i1, j1 + 1))
                if s - d >= 2 and i1 > 0:  # 向上走
                    maybe_next.append((i1 - 1, j1))
                if s - d >= 2 and j1 > 0:  # 向左走
                    maybe_next.append((i1, j1 - 1))
                if s - d >= 1:  # 原地不动
                    maybe_next.append((i1, j1))

                # 遍历所有下一步的选择
                for i2, j2 in maybe_next:
                    if maze[t + 1][i2][j2] == ".":  # 目标位置为空地
                        if dp2[i2][j2][use] is not None:
                            # 判断是否到达终点
                            if i2 == n - 1 and j2 == m - 1:
                                return True

                            if dp1[i1][j1][use] is None:
                                dp2[i2][j2][use] = None
                            else:
                                dp2[i2][j2][use] |= dp1[i1][j1][use]

                            queue2.add((i2, j2, use))
                    else:  # 目标位置为陷阱
                        # 目标位置已经被施展过永久清除术
                        if dp1[i1][j1][use] is not None and (i2, j2) in dp1[i1][j1][use]:
                            # 判断是否到达终点
                            if i2 == n - 1 and j2 == m - 1:
                                return True

                            if dp2[i2][j2][use] is not None:
                                dp2[i2][j2][use].add((i2, j2))

                            queue2.add((i2, j2, use))

                        # 施展临时清除术
                        if use is False:  # 当前还没有施展过临时清除术
                            if dp2[i2][j2][True] is not None:
                                # 判断是否到达终点
                                if i2 == n - 1 and j2 == m - 1:
                                    return True

                                if dp1[i1][j1][use] is None:
                                    dp2[i2][j2][True] = None
                                else:
                                    dp2[i2][j2][True] |= dp1[i1][j1][use]

                                queue2.add((i2, j2, True))

                        # 施展永久清除术
                        if dp1[i1][j1][use] is None:  # 当前存在没有使用过永久清除术的方法
                            # 判断是否到达终点
                            if i2 == n - 1 and j2 == m - 1:
                                return True

                            if dp2[i2][j2][use] is not None:
                                dp2[i2][j2][use].add((i2, j2))

                            queue2.add((i2, j2, use))

            dp1 = dp2
            queue1 = queue2
            t += 1

        return False