62.病毒在封闭空间中的传播时间|Marscode AI刷题

1 阅读4分钟

1.题目

问题描述

在一个封闭的房间里摆满了座位,每个座位东西向和南北向都有固定 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

2.思路

1. 初始化

  • 定义方向数组用于遍历相邻位置。
  • 准备队列用于 BFS 遍历,队列元素包含位置和感染时间。
  • 构建感染时间矩阵,初始化为无穷大,记录各位置最早感染时间。
  • 确定初始感染者位置,将其加入队列,感染时间设为 0。

2. 广度优先搜索(BFS)

  • 从队列取出元素,代表当前感染位置和时间。

  • 遍历其四个相邻位置,检查是否在矩阵内。

  • 根据相邻位置的人是否戴口罩,计算新的感染时间:

    • 未戴口罩,感染时间加 1 秒。
    • 戴口罩,通常感染时间加 2 秒,若被两个不同方向感染者同时感染,感染时间减为加 1 秒。
  • 若新感染时间更小,更新感染时间矩阵并将该位置入队。

3. 结果计算与判断

  • 遍历感染时间矩阵:

    • 若有位置感染时间仍为无穷大,说明无法感染,返回 -1。
    • 找出最大感染时间并返回。

3.代码

#include <iostream>
#include <vector>
#include <queue>
#include <limits>
#include <tuple>
using namespace std;

int solution(int row_n, int column_m, std::vector<std::vector<int>> seats, std::vector<int> patient) {
    // Please write your code here
    // 定义四个方向:右、下、左、上
    vector<pair<int, int>> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    // 使用队列进行广度优先搜索(BFS),存放的是一个 三元组 (行号, 列号, 时间)
    queue<tuple<int, int, int>> queue;
    // 记录每个位置被感染的最早时间,初始设为无穷大
    vector<vector<int>> infected_time(row_n, vector<int>(column_m, numeric_limits<int>::max()));
    // 获取初始感染者的位置
    int start_row = patient[0];
    int start_col = patient[1];
    // 将初始感染者加入队列,感染时间设为 0
    queue.push({start_row, start_col, 0});
    infected_time[start_row][start_col] = 0;

    // 进行 BFS 遍历
    while(!queue.empty()) {
        auto [r, c, time] = queue.front();
        queue.pop();

        // 遍历四个方向
        for (auto [dr, dc] : directions) {
            int nr = r + dr;
            int nc = c + dc;

            // 检查边界
            if (0 <= nr && nr < row_n && 0 <= nc && nc < column_m) {
                int new_time;

                if (seats[nr][nc] == 0) { // 未带口罩
                    new_time = time + 1;
                } else { // 戴口罩
                    new_time = time + 2;
                    int adjacent_infected = 0;

                    // 计算周围已感染的邻居数量
                    for (auto [dr2, dc2] : directions) {
                        int ar = nr + dr2;
                        int ac = nc + dc2;
                        if (0 <= ar && ar < row_n && 0 <= ac && ac < column_m && infected_time[ar][ac] == time) {
                            adjacent_infected += 1;
                        }
                    }
                    // 若被两个不同方向的感染者感染,则感染时间减少到 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.push({nr, nc, new_time});
                }
            }
        }
    }
    // 计算最晚感染的时间
    int max_time = 0;
    for (int r = 0; r < row_n; ++r) {
        for (int c = 0; c < column_m; ++c) {
            // 若某些人无法被感染,则返回 -1
            if  (infected_time[r][c] == numeric_limits<int>::max()) {
                return - 1;
            }
            max_time = max(max_time, infected_time[r][c]);
        }
    }
    return max_time;
}
int main() {
    //  You can add more test cases here
    std::vector<std::vector<int>> testSeats1 = {{0,1,1,1},{1,0,1,0},{1,1,1,1},{0,0,0,1}};
    std::vector<std::vector<int>> testSeats2 = {{0,1,1,1},{1,0,1,0},{1,1,1,1},{0,0,0,1}};
    std::vector<std::vector<int>> testSeats3 = {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
    std::vector<std::vector<int>> testSeats4 = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
    std::vector<std::vector<int>> testSeats5 = {{1}};

    std::cout << (solution(4, 4, testSeats1, {2, 2}) == 6) << std::endl;
    std::cout << (solution(4, 4, testSeats2, {2, 5}) == 0) << std::endl;
    std::cout << (solution(4, 4, testSeats3, {2, 2}) == 4) << std::endl;
    std::cout << (solution(4, 4, testSeats4, {2, 2}) == 6) << std::endl;
    std::cout << (solution(1, 1, testSeats5, {0, 0}) == 0) << std::endl;

    return 0;
}

4.参考资料

AI刷题-病毒在封闭空间中的传播时间-CSDN博客