机试题——病毒的传播

题目描述

最近病毒肆虐,科学家为了研究病毒的传播轨迹,需要设计一套简易的传播模型。在一张 ( 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

解题思路

问题分析

  1. 目标:计算未感染人群被感染的最少天数。
  2. 关键点
    • 需要模拟病毒传播过程,直到没有新的感染发生。
    • 危险系数和感染阈值影响感染过程。
    • 需要使用广度优先搜索(BFS)算法来模拟病毒传播。

算法设计

  1. 数据结构

    • 使用二维数组 g 存储地图信息。
    • 使用二维数组 d 存储每个位置的危险系数。
    • 使用二维数组 res 存储每个位置的感染天数。
  2. 初始化

    • 读取输入,初始化地图信息和危险系数。
    • 对于墙体、空地等不参与传播的格子,直接设置输出为 -1,表示这些格子不会被感染。
  3. 广度优先搜索(BFS)

    • 使用队列 q 存储当前感染者的位置。
    • 从感染者开始,逐层向外扩展,计算每个位置的危险系数。
    • 如果某个位置的危险系数大于等于感染阈值,则该位置的人会被感染。
  4. 多源BFS的实现

    • 当找到一个新的感染源时,立刻将其加入队列,并再次进行BFS,更新整个危险系数矩阵,确保病毒从多个感染源同时向外传播。
  5. 停止条件

    • 当队列为空,即所有可能被感染的人都已传播完毕,或者无法再传播时,停止模拟,输出结果。
  6. 输出结果

    • 对于每个格子,如果它最终没有被感染,输出 -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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值