问题描述
在一个封闭的房间中,排列着 n 行 m 列的座位,每个座位间距为 1 米。房间中每个座位上都坐着一人,部分人戴了口罩,部分人未戴口罩。已知房间中有一位已经感染病毒的人,病毒可以每秒向相邻座位传播 1 米。对于戴口罩的人,病毒需要两秒才能成功感染,或者需要在一秒内从两个相邻的感染者处同时被感染。设计一个算法,计算病毒感染房间内所有人所需的最短时间。
测试样例
样例1:
输入:
row_n = 4, column_m = 4, seats = [[0, 1, 1, 1], [1, 0, 1, 0], [1, 1, 1, 1], [0, 0, 0, 1]], patient = [2, 2]
输出:6
样例2:
输入:
row_n = 3, column_m = 3, seats = [[0, 0, 0], [0, 1, 0], [0, 0, 0]], patient = [2, 2]
输出:4
样例3:
输入:
row_n = 5, column_m = 5, seats = [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]], patient = [3, 3]
输出:7
答案
from collections import deque
def solution(row_n, column_m, seats, patient):
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
queue = deque()
infected_time = [[float('inf')] * column_m for _ in range(row_n)]
start_row, start_col = patient
queue.append((start_row, start_col, 0)) # (行, 列, 时间)
infected_time[start_row][start_col] = 0
while queue:
r, c, time = queue.popleft()
for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < row_n and 0 <= nc < column_m:
if seats[nr][nc] == 0: # 未戴口罩
new_time = time + 1
else: # 戴口罩
new_time = time + 2
adjacent_infected = 0
for dr2, dc2 in directions:
ar, ac = nr + dr2, nc + dc2
if 0 <= ar < row_n and 0 <= ac < column_m and infected_time[ar][ac] == time:
adjacent_infected += 1
if adjacent_infected >= 2:
new_time = min(new_time, time + 1)
if new_time < infected_time[nr][nc]:
infected_time[nr][nc] = new_time
queue.append((nr, nc, new_time))
max_time = 0
for r in range(row_n):
for c in range(column_m):
if infected_time[r][c] == float('inf'):
return -1 # 表示有些人无法感染
max_time = max(max_time, infected_time[r][c])
return max_time
# 测试样例
print(solution(4, 4, [[0, 1, 1, 1], [1, 0, 1, 0], [1, 1, 1, 1], [0, 0, 0, 1]], [2, 2])) # 输出: 6
print(solution(3, 3, [[0, 0, 0], [0, 1, 0], [0, 0, 0]], [2, 2])) # 输出: 4
print(solution(5, 5, [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]], [3, 3])) # 输出: 7
这道题的核心在于模拟病毒传播的过程,其中不同的传播条件导致传播速度不同。我们可以采用广度优先搜索(BFS)算法来遍历每一个位置,记录到达每个位置的最短时间。在这个问题中,BFS非常适合处理多层级传播或障碍等复杂传播路径。
解题思路
BFS实现细节
在BFS的实现中,可以使用一个队列来存储每个被感染的座位位置和当前传播的时间。例如,队列的每个元素可以表示为 (x, y, time)
,即表示当前感染的坐标和传播的时间。在每次从队列中取出一个位置时,可以根据条件传播到四周相邻的座位。
初始化感染矩阵
为了实现有效的BFS遍历,我们需要一个感染时间矩阵 infect_time
。该矩阵用于记录每个位置的最短感染时间。初始化时,所有位置的时间都设置为-1,表示这些位置尚未被感染。
处理传播条件
在BFS遍历过程中,需对每个相邻座位检查感染条件:
- 未戴口罩:若位置
seats[nx][ny]
表示未戴口罩,病毒传播时间为time + 1
。如果infect_time[nx][ny] == -1
或time + 1 < infect_time[nx][ny]
,则更新该位置的感染时间并将其加入队列。 - 戴口罩:对于戴口罩的座位,如果
infect_time[nx][ny] == -1
或time + 2 < infect_time[nx][ny]
,则更新该位置的感染时间为time + 2
,并将其加入队列。同时在BFS遍历时,需检查该位置的相邻节点,看是否可以同时被两个感染源感染。
BFS伪代码流程
python
复制代码
初始化 infect_time 矩阵为 -1
将感染源位置加入队列,设置其感染时间为 0
while 队列不为空:
取出队列中第一个元素 (x, y, time)
遍历 (x, y) 的四个相邻座位:
if 相邻位置未被感染:
if 相邻位置未戴口罩:
更新感染时间为 time + 1,并将其加入队列
elif 相邻位置戴口罩:
if 两个相邻感染源可以同时感染:
更新感染时间为 time + 1
else:
更新感染时间为 time + 2,并将其加入队列
优化与边界处理
- 多源感染优化:在BFS搜索过程中,遇到戴口罩的座位时,需要检查其是否满足双源感染条件。如果满足,可以将传播时间降低为1秒。
- 边界检测:在访问相邻位置时,必须确保坐标在矩阵范围内,否则可能导致索引越界。
- 最短传播时间记录:遍历完成后,
infect_time
中每个位置记录的就是其最短感染时间。可以通过扫描infect_time
矩阵,找到最大时间作为结果。