病毒在封闭空间中的传播时间| 豆包MarsCode AI刷题

253 阅读4分钟

题目描述

在一个封闭的房间中,排列着 n 行 m 列的座位,每个座位间距为 1 米。 房间中每个座位上都坐着一人,部分人戴了口罩,部分人未戴口罩。已知房间中有一位已经感染病毒的人,病毒可以每秒向相邻座位传播 1 米。对于戴口罩的人,病毒需要两秒才能成功感染,或者需要在一秒内从两个相邻的感染者处同时被感染。设计一个算法,计算病毒感染房间内所有人所需的最短时间

这个题意描述还是挺清楚的,简单来说就是一个传染源能传染四个方向的邻居,而戴口罩的人需要传染两次,无论是两个人同时传还是一个人传染两次,而被传染的人又会成为新的传染源,在下一波开始传染新的人

而具体到给出的数据,这里补充几点题目中没有讲清楚的事情:

  1. 对于数组中的数,0为没戴口罩,1为戴口罩的人
  2. 给出的病人坐标可能违规,即超出数组边界(见test2)

思路讲解

(水平有限,如果大佬们有更厉害的解法欢迎狠狠的指出来)

在理解了题意之后,关注到这个题中的传染和图的遍历有许多相似之处,特殊之处在于,对于某些特殊“节点”,需要走两次才能完成遍历。又注意到每个病人的传染范围都只有“一步”的距离,即传染是逐层扩散的,且要求出完成传染的最短时间,因此采用BFS的思路也就比较自然了

在确定了大体思路后,我们再来看看怎么使用BFS做这道题。一些比较经典的操作不再赘述,有需要可以参考BFS——广度优先算法(Breadth First Search)-CSDN博客

这里主要讲一下这道题和经典BFS的区别

  1. 一个病人如果传染的人戴了口罩,那么他就需要再传染一次,因此,这道题里面是允许多个节点重复遍历的,仅用队列装所有的病人作为约束就行。上述描述虽然没有提及一个戴口罩的人被两个人同时传染的情况,但实际上除非一个病人下一步传染的所有戴口罩的人都同时被两个病人夹击,否则这个病人都是要再次进入队列进行第二次遍历。当然,如果想要进一步优化,对于类似于上面提到的特殊情况当然可以剪枝
  2. 这道题另外一个比较重要的事情就是关于时间的记录。直接记录时间的话会有点麻烦,因此这里选择把当前时间作为节点的一个属性存进队列里,并在每一轮遍历的时候取出。而当while循环结束时,最后去到的时间就是传染完所有人所需的最短时间

代码实现

    dirx = [0,0,-1,1]
    diry = [1,-1,0,0]
    def solution(row_n, column_m, seats, patient):
        q = []
        px, py = patient[0], patient[1]
        if px<0 or px>=row_n or py<0 or py>=column_m:  # 错误数据特判
            return 0
        seats[px][py] = -1 # 病人
        q.append((px,py,0))
        res=0
        while q:
            x,y,t = q.pop(0)
            res=t
            for i in range(4):
                xx = x+dirx[i]
                yy = y+diry[i]
                if xx<row_n and yy<column_m and xx>=0 and yy>=0:
                    if seats[xx][yy] == 1:
                        seats[xx][yy] -= 1
                        q.append((x,y,t+1))
                    elif seats[xx][yy] == 0:
                        seats[xx][yy] -= 1
                        q.append((xx,yy,t+1))
        return res

    if __name__ == "__main__":
        #  You can add more test cases here
        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 )

总结

(应该水够字数了……) 其实会比较好奇这次题目的难度划分,感觉有些简单题好像还会难一点()