病毒感染时间题解

74 阅读4分钟

问题描述 病毒感染时间

在一个封闭的房间里摆满了座位,每个座位东西向和南北向都有固定 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. 未感染、无口罩:被感染需要 1 秒。
  2. 未感染、戴口罩:被感染需要 2 秒,或者在 1 秒内被两个人分别感染一次(破掉两层护盾)。
  3. 已感染:跳过,已感染的人可以传播病毒,不再需要进行处理。

详细步骤

  1. 初始化变量和数据结构

    • 使用一个二维数组 time 来记录每个座位感染所需的时间,初始值为无穷大(表示尚未感染)。
    • 使用一个队列 queue 存储待感染的人的位置和当前感染到达该人的时间。
    • 定义方向数组 directions 表示四个可能传播的方向:上、下、左、右。
  2. 将初始感染源加入队列

    • 把已感染的起始位置 (x, y) 加入 queue,并将其感染时间设为 0
  3. 广度优先搜索 (BFS)

    • 使用 BFS 来模拟病毒传播过程,按层次逐步传播。

    • 每次从 queue 中取出一个位置 (i, j) 和它的感染时间 t

    • 遍历四个方向,计算相邻位置 (ni, nj) 的状态,并判断是否可以被感染。

      • 无口罩的情况:直接传播,新的感染时间为 t + 1

      • 戴口罩的情况

        • 如果这是第一次传播到该位置,记录 t + 1 并作为破盾时间。
        • 如果已经破盾一次,再次传播时设为 t + 1(即总共 2 秒后感染成功)。
    • 将新感染的节点加入 queue,并更新 time 数组。

  4. 计算感染所需的总时间

    • 遍历 time 数组中的最大值,即为感染所有人所需的时间。
  5. 特殊情况处理

    • 如果整个房间内的人无法被感染,返回 -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 )