问题描述
在一个封闭的房间中,排列着 n 行 m 列的座位,每个座位间距为 1 米。房间中每个座位上都坐着一人,部分人戴了口罩,部分人未戴口罩。已知房间中有一位已经感染病毒的人,病毒可以每秒向相邻座位传播 1 米。对于戴口罩的人,病毒需要两秒才能成功感染,或者需要在一秒内从两个相邻的感染者处同时被感染。设计一个算法,计算病毒感染房间内所有人所需的最短时间。
题意解析
给定一个元素为0或1的矩阵,一个起始点p,感染的过程就是使感染点的上下左右四个点从未感染状态变为已感染,对于元素为0的点只需要感染一次,对于元素为1的点需要感染两次。对于每一次每个点只能进行一次感染。最终目标是计算出这个矩阵的所有点被感染的时间。
解决思路
由于矩阵内元素均为0或1,且对于元素为0的点只需要感染一次,对于元素为1的点需要感染两次,可以将感染这个过程抽象为元素值减一,即如果矩阵内的元素值变为-1,则说明其已被感染。将值为-1的点用一个数列保存起来,每次感染便是从这些点开始计算其上下左右四个方向,若这些方向的点的值不为-1,则令其值减一,并加入到被感染的数列中。
对于一开始给定的起始点,需要将其标记为已感染,更改其值为-1。
完整代码
下面的代码使用豆包AI自动格式化(为什么大括号要换行)
#include <iostream>
#include <vector>
bool isValid(int i, int j, int m, int n)
{
return (i >= 0 && i < m && j >= 0 && j < n);
}
int solution(int row_n, int column_m, std::vector<std::vector<int>> seats,std::vector<int> patient) {
if (!isValid(patient[0], patient[1], row_n, column_m))
return 0;
int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
std::vector<std::pair<int, int>> q;
q.push_back({patient[0], patient[1]});
seats[patient[0]][patient[1]] = -1;
int days = 0;
int patient_num = 1;
while (patient_num < row_n * column_m)
{
int size = q.size();
for (int i = 0; i < size; ++i)
{
int x = q[i].first;
int y = q[i].second;
for (const auto &dir : directions)
{
int newX = x + dir[0];
int newY = y + dir[1];
if (isValid(newX, newY, row_n, column_m) && seats[newX][newY] >= 0)
{
seats[newX][newY]--;
if (seats[newX][newY] == -1)
{
q.push_back({newX, newY});
patient_num++;
}
}
}
}
days++;
}
return days;
}
可优化
1、如果所有座位都感染了,可以提前终止循环,而不是继续遍历数组。
2、如果这个点的上下左右都被感染了,则直接跳过该点即可。
3、可以使用标记数组来标记访问过的座位,以避免直接修改seats数组。
AI 刷题的帮助
在解决这类问题时,豆包marscode AI可以提供以下优势:
- 代码生成:AI能够根据问题描述快速生成相应的代码框架,节省编写代码的时间。
- 算法优化:AI能够分析代码并提供可能的优化建议,帮助提高算法的效率。
- 错误检测:AI能够检测代码中的错误,并提供修改建议,确保代码的正确性。