题目描述
最近病毒肆虐,科学家为了研究病毒的传播轨迹,需要设计一套简易的传播模型。在一张 ( M \times N ) 地图中,包含墙体、空地、已感染的人(不戴口罩)、已感染的人(戴口罩)、未感染的人(不戴口罩)、未感染的人(戴口罩)。科学家会设置一些危险系数,以及感染阈值。然后观察未感染人群大概多少天以后会被感染。
输入描述
第一行:包含五个整数 ( M, N, a1, a2, b1, b2 ),用空格隔开,其中:
- ( M ) 和 ( N ) 分别表示地图的行数和列数。
- ( a1 ) 和 ( a2 ) 分别表示戴口罩和不戴口罩时的危险系数。
- ( b1 ) 和 ( b2 ) 分别表示戴口罩和不戴口罩时的感染阈值。
第二行到第 ( M+2 ) 行:包含 ( M ) 行 ( N ) 列地图数据信息。
输出描述
输出 ( M ) 行 ( N ) 列数据信息,每个位置需要输出的内容如下:
- 该位置没有人(空地或者墙壁)的话则返回
-1
。 - 该位置的人初始态时就被感染了的话,则填
0
。 - 该位置的人初始没有被感染,但是最终被感染,则填被感染的天数。
- 该位置的人没有被感染,则返回
-1
。
用例输入
输入:
3 4 7 10 6 2
0 0 0 0
2 0 1 5
0 0 0 0
输出:
-1 -1 -1 -1
0 -1 -1 -1
-1 -1 -1 -1
解题思路
问题分析
- 目标:计算未感染人群被感染的最少天数。
- 关键点:
- 需要模拟病毒传播过程,直到没有新的感染发生。
- 危险系数和感染阈值影响感染过程。
- 需要使用广度优先搜索(BFS)算法来模拟病毒传播。
算法设计
-
数据结构:
- 使用二维数组
g
存储地图信息。 - 使用二维数组
d
存储每个位置的危险系数。 - 使用二维数组
res
存储每个位置的感染天数。
- 使用二维数组
-
初始化:
- 读取输入,初始化地图信息和危险系数。
- 对于墙体、空地等不参与传播的格子,直接设置输出为
-1
,表示这些格子不会被感染。
-
广度优先搜索(BFS):
- 使用队列
q
存储当前感染者的位置。 - 从感染者开始,逐层向外扩展,计算每个位置的危险系数。
- 如果某个位置的危险系数大于等于感染阈值,则该位置的人会被感染。
- 使用队列
-
多源BFS的实现:
- 当找到一个新的感染源时,立刻将其加入队列,并再次进行BFS,更新整个危险系数矩阵,确保病毒从多个感染源同时向外传播。
-
停止条件:
- 当队列为空,即所有可能被感染的人都已传播完毕,或者无法再传播时,停止模拟,输出结果。
-
输出结果:
- 对于每个格子,如果它最终没有被感染,输出
-1
;如果被感染,则输出感染发生的天数;对于初始感染的格子,输出0
。
- 对于每个格子,如果它最终没有被感染,输出
代码实现
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<set>
#include<list>
#include<sstream>
#include<bitset>
#include<stack>
#include<climits>
#include<iomanip>
#include<cstdint>
using namespace std;
#define maxn 10005
int m, n, a1, b1, a2, b2;
int dx[4] = { 1, -1, 0, 0 }; // 四个方向:上、下、左、右
int dy[4] = { 0, 0, 1, -1 }; // 对应的Y轴变化
int g[maxn][maxn], d[maxn][maxn], res[maxn][maxn];
void print(vector<int> nums) {
for (int i = 0; i < nums.size(); i++) {
cout << nums[i];
if (i != nums.size() - 1) cout << " ";
}
}
vector<pair<int, int>> bfs(queue<pair<int, int>>& q) {
vector<pair<int, int>> newcur;
while (!q.empty())
{
int cx = q.front().first;
int cy = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int nx = cx + dx[i], ny = cy + dy[i];
if (nx >= 0 && nx < m && ny >= 0 && ny < n &&g[nx][ny] != 1 && d[nx][ny] < d[cx][cy] - 1)
{
d[nx][ny] = d[cx][cy] - 1;
// 判断当前位置会不会有感染的
if ((d[nx][ny] >= b1 && g[nx][ny] == 5) || // 未感染戴口罩
(d[nx][ny] >= b2 && g[nx][ny] == 4)) { // 未感染不戴口罩
newcur.push_back({ nx, ny }); // 将感染的人加入新增感染列表
}
q.push({ nx, ny });
}
}
}
return newcur;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
queue<pair<int, int>> q;
cin >> m >> n >> a1 >> a2 >> b1 >> b2;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cin >> g[i][j];
if (g[i][j] == 2) {
d[i][j] = a2;
q.push({ i, j });
res[i][j] = 0;
}
else if (g[i][j] == 3) {
d[i][j] = a1;
q.push({ i, j });
res[i][j] = 0;
}
else {
res[i][j] = -1;
}
}
}
int days = 0;
while (!q.empty()) {
days++;
//cout << days << endl;
vector<pair<int, int>> newcur = bfs(q);
for (int i = 0; i < newcur.size(); i++) {
// 新增感染
int x = newcur[i].first, y = newcur[i].second;
res[x][y] = days;
// 更新不戴口罩感染者的危险系数
if (g[x][y] == 4 && d[x][y] < a2) {
d[x][y] = a2;
q.push({ x, y });
}
// 更新戴口罩感染者的危险系数
else if (g[x][y] == 5 && d[x][y] < a1) {
d[x][y] = a1;
q.push({ x, y });
}
if (g[x][y] == 4) g[x][y] = 2;
if (g[x][y] == 5) g[x][y] = 3;
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cout << res[i][j];
if (j != n - 1) cout << " ";
}
if(i!=m-1) cout << "\n";
}
return 0;
}