计算疫情扩散时间

一、题目描述

在一个地图中(地图由n*n个区域组成),有部分区域被感染病菌。 感染区域每天都会把周围(上下左右)的4个区域感染。

请根据给定的地图计算,多少天以后,全部区域都会被感染。 如果初始地图上所有区域全部都被感染,或者没有被感染区域,返回-1

二、输入输出描述

输入描述

一行N*N个数字(只包含0,1,不会有其他数字,1<=N<200)表示一个地图,数字间用,分割,0表示未感染区域,1表示已经感染区域;

每N个数字表示地图中一行,输入数据共表示N行N列的区域地图。

例如输入1,0,1,0,0,0,1,0,1,表示地图

复制代码
1,0,1
0,0,0
1,0,1
输出描述

一个整数,表示全部感染所需天数;特殊情况返回 -1。

三、示例

|----|--------------------------------|
| 输入 | 1,0,1,0,0,0,1,0,1 |
| 输出 | 2 |
| 说明 | 1天以后,地图中仅剩余中心点未被感染;2天以后,全部被感染。 |

|----|-------------------|
| 输入 | 1,1,1,1,1,1,1,1,1 |
| 输出 | -1 |
| 说明 | 全部都感染 |

四、解题思路

1. 核心思想

采用广度优先搜索(BFS) 模拟感染的层级扩散过程:

  • BFS 的核心优势:按 "层" 遍历(每一层对应一天的扩散),能精准统计扩散的天数;
  • 初始感染区域作为 BFS 的起始节点,每一轮处理队列中的所有节点(当天待扩散的区域),感染相邻健康区域并将新感染区域加入队列(下一天扩散),直到所有健康区域被感染或队列为空。
2. 问题本质分析

这个问题的核心是 **"无权图的最短路径 / 层级遍历"**:

  • 二维矩阵可看作一个无权图,每个单元格是一个节点,相邻单元格(上下左右)是边;
  • 初始感染节点到所有健康节点的 "最短路径长度" 的最大值,就是所有区域被感染的总天数;
  • 特殊情况:无初始感染节点(全健康)或无健康节点(全感染),返回 - 1。
3. 核心逻辑
  1. 数据转换:将一维输入转为 n×n 二维矩阵,明确矩阵的空间结构;
  2. 初始化:
    • 统计健康区域总数,判断特殊情况;
    • 收集所有初始感染区域,作为 BFS 的起始队列;
  3. BFS 扩散:
    • 按层处理队列中的感染区域,每处理一个区域,感染其四个方向的健康区域;
    • 标记新感染区域的天数,并将其加入队列待后续扩散;
    • 每轮扩散后更新剩余健康区域数量,直到健康区域为 0;
  4. 结果计算:返回最大扩散天数(需修正计数偏差)。
4. 步骤拆解
  1. 输入处理:读取逗号分隔的字符串,转为一维整数列表;
  2. 矩阵转换
    • 计算矩阵边长n = √(列表长度)
    • 将一维列表转为 n×n 二维矩阵;
  3. 初始化参数
    • 队列存储初始感染区域坐标;
    • 统计健康区域数量healthy
    • 定义上下左右四个方向的偏移量;
  4. 特殊情况判断 :若healthy=0(全感染)或healthy=n×n(全健康),返回 - 1;
  5. BFS 扩散循环
    • 取出队列中的感染区域坐标,计算下一轮扩散天数day
    • 遍历四个方向,校验新坐标的边界和健康状态;
    • 感染健康区域:healthy--,标记感染天数,将新坐标加入队列;
    • 直到队列为空或healthy=0
  6. 结果返回 :返回day-1(修正天数计数偏差)。

五、代码实现

java 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        List<Integer> map = new ArrayList<>();
        int pos = 0;
        String token;
        while ((pos = input.indexOf(",")) != -1) { // 将输入字符串转换为一维数组
            token = input.substring(0, pos);
            map.add(Integer.parseInt(token));
            input = input.substring(pos + 1);
        }
        map.add(Integer.parseInt(input));
        System.out.println(getInfectionDays(map)); // 输出感染天数
    }

    public static int getInfectionDays(List<Integer> map) {
        int n = (int) Math.sqrt(map.size());

        int[][] matrix = new int[n][n]; // 将一维数组转换为二维矩阵

        Queue<int[]> q = new LinkedList<>(); // 用队列存储感染区域

        int healthy = 0; // 记录未感染区域数量

        int[][] offsets = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 记录四个方向的偏移量

        for (int i = 0; i < n * n; i++) {
            int x = i / n;
            int y = i % n;
            matrix[x][y] = map.get(i); // 将一维数组转换为二维矩阵
            if (matrix[x][y] == 1) {
                q.offer(new int[]{x, y}); // 将感染区域加入队列
            } else {
                healthy++; // 计算未感染区域数量
            }
        }

        if (healthy == 0 || healthy == n * n) { // 判断特殊情况
            return -1;
        }

        int day = 0; // 记录感染天数
        while (!q.isEmpty() && healthy > 0) { // 当队列不为空且还有未感染区域时,进行循环
            int[] tmp = q.poll(); // 取出队首元素
            int x = tmp[0], y = tmp[1]; // 获取队首元素的坐标
            day = matrix[x][y] + 1; // 记录感染天数

            for (int[] offset : offsets) { // 遍历四个方向
                int newX = x + offset[0]; // 新的横坐标
                int newY = y + offset[1]; // 新的纵坐标

                if (newX >= 0 && newX < n && newY >= 0 && newY < n && matrix[newX][newY] == 0) { // 判断边界和未感染区域
                    healthy--; // 未感染区域数量减一
                    matrix[newX][newY] = day; // 标记该区域已感染
                    q.offer(new int[]{newX, newY}); // 将该区域加入队列
                }
            }
        }

        return day - 1; // 返回感染天数
    }
}
相关推荐
2601_949809592 小时前
flutter_for_openharmony家庭相册app实战+我的Tab实现
java·javascript·flutter
24zhgjx-lxq2 小时前
华为ensp:MSTP
网络·安全·华为·hcip·ensp
vx_BS813302 小时前
【直接可用源码免费送】计算机毕业设计精选项目03574基于Python的网上商城管理系统设计与实现:Java/PHP/Python/C#小程序、单片机、成品+文档源码支持定制
java·python·课程设计
2601_949868362 小时前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
飞机和胖和黄2 小时前
考研之王道C语言第三周
c语言·数据结构·考研
yyy(十一月限定版)2 小时前
寒假集训4——二分排序
算法
星火开发设计2 小时前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
蒹葭玉树3 小时前
【C++上岸】C++常见面试题目--操作系统篇(第二十八期)
linux·c++·面试
醉颜凉3 小时前
【LeetCode】打家劫舍III
c语言·算法·leetcode·树 深度优先搜索·动态规划 二叉树