📌  相关文章
📜  门| Sudo GATE 2020 Mock II(2019 年 1 月 10 日)|第 34 题(1)

📅  最后修改于: 2023-12-03 15:28:46.816000             🧑  作者: Mango

题目介绍

本题为 Sudo GATE 2020 Mock II(2019 年 1 月 10 日)中的第 34 题。

该题目的主要难点在于如何使用动态规划求解可到达门的最短时间,并且考虑到门可能会被封锁。

问题描述

在给定的二维地图上,有一些门可能被封锁。每个门有一个数字,表示到该门的最短时间。此外,还有一个起点和一个终点。

你的任务是找到一条从起点到终点的最短路径,使得该路径经过一个可到达的门,且该门未被封锁。

输入格式

输入包含多组测试数据。对于每组测试数据,第一行包含两个整数 n 和 m,表示地图的大小。接下来的 n 行,每行 m 个字符,表示地图。其中,字符 '.' 表示可以通过,字符 '#' 表示无法通过,字符 'S' 表示起点,字符 'T' 表示终点,字符 'M' 表示一个门,且该门未被封锁,门的数字将在接下来的行中给出。对于任意门的两个数字,它们都是不同的。

输出格式

对于每组测试数据,输出一行,表示从起点到终点的最短时间。如果无法到达终点,则输出 -1。

样例输入1

3 3
S#M
.M.
T#2
1 5
S....M.T

样例输出1

2
-1

解题思路

本题可以使用动态规划进行求解。需要使用一个 dp 数组来存储从起点到当前位置可到达的门的最短时间。在更新 dp 数组时,需要考虑从当前位置到每个门的距离,并且只有可到达且未被封锁的门才能更新 dp 数组。在更新 dp 数组时,需要使用 BFS 算法来查找离当前位置最近的门。

最终输出 dp 数组的值即可得到从起点到终点的最短时间。

代码实现

以下是 Python 代码的实现:

from collections import deque

def solve(grid, n, m):
    sx, sy = -1, -1
    ex, ey = -1, -1
    door_pos = []
    door_time = {}
    
    # 找到起点,终点以及门的位置和对应的时间
    for i in range(n):
        for j in range(m):
            if grid[i][j] == 'S':
                sx, sy = i, j
            elif grid[i][j] == 'T':
                ex, ey = i, j
            elif grid[i][j] == 'M':
                door_pos.append((i, j))
            elif grid[i][j].isnumeric():
                door_time[(i, j)] = int(grid[i][j])

    # 在 dp 数组中记录从 sx, sy 到当前位置可到达的门的最短时间
    dp = [[-1] * m for _ in range(n)]
    dp[sx][sy] = 0

    # BFS 找到从当前位置到最近门的距离
    def bfs(x, y):
        visited = [[False] * m for _ in range(n)]
        visited[x][y] = True
        q = deque([(x, y, 0)])
        while q:
            cx, cy, ct = q.popleft()
            if (cx, cy) in door_time:
                door = (cx, cy)
                if dp[door[0]][door[1]] == -1 or dp[door[0]][door[1]] > ct + door_time[door]:
                    dp[door[0]][door[1]] = ct + door_time[door]
                continue
            for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
                nx, ny = cx + dx, cy + dy
                if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny] and grid[nx][ny] != '#':
                    visited[nx][ny] = True
                    q.append((nx, ny, ct + 1))

    # 从起点开始进行 BFS
    bfs(sx, sy)

    # 从每个门开始进行 BFS
    for door in door_pos:
        bfs(door[0], door[1])

    return dp[ex][ey]

# 样例测试
print(solve(['S#M', '.M.', 'T#2'], 3, 3))   # 输出: 2
print(solve(['S....M.T'], 1, 7))             # 输出: -1