📅  最后修改于: 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。
3 3
S#M
.M.
T#2
1 5
S....M.T
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