问题描述 病毒感染时间
在一个封闭的房间里摆满了座位,每个座位东西向和南北向都有固定 1 米的间隔。座位上坐满了人,坐着的人可能带了口罩,也可能没有带口罩。我们已经知道房间里的某个人已经感染了病毒,病毒的传播速度是每秒钟感染距离 1 米,但是超出 1 米病毒没有感染效力。病毒对于戴口罩的人需要两秒钟,或者一秒内被周围的两个人分别感染一次,才能被病毒感染。请实现一个算法,计算出来在给定的人员戴口罩情况,以及已经感染的人员位置情况下,病毒感染屋内所有人所需的时间。假定,已经感染的人戴和不戴口罩都具有相同的感染能力。
输入格式
第一行两个整数 n, m,表示座位有 n 行 m 列
接下来 n 行,每行 m 个整数 T(i, j)表示座位上的人戴口罩情况,0 表示未戴口罩,1 表示戴了口罩
最后一行两个整数 x, y 表示已经感染病毒的人所在座位
输出格式
输出一个整数表示病毒感染屋内所有人所需的时间
输入样例
4 4
0 1 1 1
1 0 1 0
1 1 1 1
0 0 0 1
2 2
输出样例
6
数据范围
座位横向和纵向最多 255
解题思路
本题可以使用 广度优先搜索 (BFS) 算法来模拟病毒的传播过程。由于病毒传播速度固定,且每一秒钟会感染周围的 1 米范围内的座位,我们可以将感染的人按时间顺序加入队列中,并逐层传播病毒,直到感染所有人。
我们可以将座位的感染状态分为以下几种情况:
- 未感染、无口罩:被感染需要 1 秒。
- 未感染、戴口罩:被感染需要 2 秒,或者在 1 秒内被两个人分别感染一次(破掉两层护盾)。
- 已感染:跳过,已感染的人可以传播病毒,不再需要进行处理。
详细步骤
-
初始化变量和数据结构:
- 使用一个二维数组
time来记录每个座位感染所需的时间,初始值为无穷大(表示尚未感染)。 - 使用一个队列
queue存储待感染的人的位置和当前感染到达该人的时间。 - 定义方向数组
directions表示四个可能传播的方向:上、下、左、右。
- 使用一个二维数组
-
将初始感染源加入队列:
- 把已感染的起始位置
(x, y)加入queue,并将其感染时间设为0。
- 把已感染的起始位置
-
广度优先搜索 (BFS) :
-
使用 BFS 来模拟病毒传播过程,按层次逐步传播。
-
每次从
queue中取出一个位置(i, j)和它的感染时间t。 -
遍历四个方向,计算相邻位置
(ni, nj)的状态,并判断是否可以被感染。-
无口罩的情况:直接传播,新的感染时间为
t + 1。 -
戴口罩的情况:
- 如果这是第一次传播到该位置,记录
t + 1并作为破盾时间。 - 如果已经破盾一次,再次传播时设为
t + 1(即总共 2 秒后感染成功)。
- 如果这是第一次传播到该位置,记录
-
-
将新感染的节点加入
queue,并更新time数组。
-
-
计算感染所需的总时间:
- 遍历
time数组中的最大值,即为感染所有人所需的时间。
- 遍历
-
特殊情况处理:
- 如果整个房间内的人无法被感染,返回
-1。
- 如果整个房间内的人无法被感染,返回
代码实现
from collections import deque
def solution(row_n, column_m, seats, patient):
patient_num = 1
x, y = patient
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
queue = []
queue.append((x, y))
seats[x][y] = -1 # 标记起始病人为已感染
time = 0
while queue:
# print(seats)
if patient_num == row_n*column_m:
return time
# print(patient_num)
new_patient = []
remove_queue = []
for index, (i, j) in enumerate(queue): # 遍历一轮病人
now_count = 0
# print(queue)
for di, dj in directions:
ni, nj = i + di, j + dj
if ni < 0 or ni >= row_n or nj < 0 or nj >= column_m: # 越界
now_count += 1
# print("越界")
else:
if seats[ni][nj] == -1: # 已经被感染
now_count += 1
elif seats[ni][nj] == 0: # 没戴口罩,直接感染
new_patient.append((ni, nj))
seats[ni][nj] = -1
now_count += 1
patient_num += 1
elif seats[ni][nj] == 1: # 戴口罩了,第一次,可以理解为让其摘下了口罩
seats[ni][nj] = 0
#print("now_count:",now_count)
if now_count >= 4:
# 已经感染完了,让这个病人出队
# queue.pop(index)
remove_queue.append(index)
# 处理需要出队的
for i in sorted(remove_queue, reverse=True):
queue.pop(i)
# 处理新感染的
for np in new_patient:
queue.append(np)
# print("new seat:",seats)
time += 1
# return time
if __name__ == "__main__":
testSeats1 = [[0,1,1,1],[1,0,1,0],[1,1,1,1],[0,0,0,1]]
testSeats2 = [[0,1,1,1],[1,0,1,0],[1,1,1,1],[0,0,0,1]]
testSeats3 = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
testSeats4 = [[1,1,1,1],[1,1,1,1],[1,1,1,1],[1,1,1,1]]
testSeats5 = [[1]]
print(solution(4, 4, testSeats1, [2, 2]) == 6 )
# print(solution(4, 4, testSeats2, [2, 5]) == 0 )
print(solution(4, 4, testSeats3, [2, 2]) == 4 )
print(solution(4, 4, testSeats4, [2, 2]) == 6 )
print(solution(1, 1, testSeats5, [0, 0]) == 0 )