精准核酸检测
一、题目背景
为了达到新冠疫情精准防控的需要,避免全员核酸检测带来的浪费,需要精准圈定可能被感染的人群。题目通过传染病流调以及大数据分析,给出了每个人之间在时间、空间上是否存在轨迹交叉的信息,要求找出需要进行核酸检测的人员数量。
二、输入描述
总人数N:表示参与统计的总人数。
确诊病例人员编号:用逗号分隔的确诊病例人员编号列表,数量小于N。
接触矩阵:一个N*N的矩阵,表示每个人员之间是否有接触。0表示没有接触,1表示有接触。
三、输出描述
输出一个整数,表示需要进行核酸检测的人数(不包括确诊病例自身)。
package com.study.algorithm.huaweiOrOD.huaweiOD202509082334.精准核酸检测;import lombok.Data;
import lombok.extern.slf4j.Slf4j;import java.util.Arrays;
import java.util.Stack;/*** @ProjectName: algorithm* @ClassName: PreciseNucleicAcidTesting* @Description: 精准核酸检测 - 根据确诊病例和接触关系,找出所有需要核酸检测的人员* @Author: Tony_Yi* @Date: 2025/10/9 22:22* @Version 1.0**/
@Data
@Slf4j
public class PreciseNucleicAcidTesting {public static void main(String[] args) {// 测试数据int n = 10; // 总人数,人员编号从0到9int[] confirmedCases = {0, 2}; // 初始确诊病例编号int[][] contacts = { // 接触关系数组,每个子数组表示一次接触的两个人{0, 1}, {0, 2}, {1, 3}, {2, 4}, {2, 5},{3, 6}, {5, 7}, {5, 8}, {7, 9}};// 调用算法计算需要核酸检测的人数int count = methodThree(n, confirmedCases, contacts);System.out.println("需要进行核酸检测的人数: " + count);}/*** 方法三:使用深度优先搜索(DFS)模拟疫情传播,找出所有需要核酸检测的人员** @param n 总人数* @param confirmedCases 初始确诊病例编号数组* @param contacts 接触关系二维数组,每行表示一次接触的两个人* @return 需要进行核酸检测的人数(不包括初始确诊病例)*/public static int methodThree(int n, int[] confirmedCases, int[][] contacts) {// 使用栈来实现DFS遍历(深度优先搜索)Stack<Integer> stack = new Stack<>();// 访问标记数组,记录哪些人员已经被感染或需要检测boolean[] visited = new boolean[n];// 初始化:将所有初始确诊病例入栈并标记为已访问for (int caseId : confirmedCases) {stack.push(caseId); // 将确诊病例加入待处理栈visited[caseId] = true; // 标记该人员为已感染}// DFS遍历:处理栈中的每个感染人员,查找他们的接触者while (!stack.isEmpty()) {// 从栈顶取出当前处理的感染人员Integer current = stack.pop();// 遍历所有接触关系,查找与当前人员有接触的人for (int[] contact : contacts) {// 情况1:当前感染人员是接触关系的第一个人员if (contact[0] == current) {int next = contact[1]; // 接触的另一个人// 如果这个接触者还没有被标记为感染if (!visited[next]) {stack.push(next); // 将其加入待处理栈visited[next] = true; // 标记为已感染}// 记录日志:显示感染传播路径log.info("-------------------");log.info("当前节点:{}, 邻居节点:{}", current, next);}// 情况2:当前感染人员是接触关系的第二个人员else if (contact[1] == current) {int next = contact[0]; // 接触的另一个人// 如果这个接触者还没有被标记为感染if (!visited[next]) {stack.push(next); // 将其加入待处理栈visited[next] = true; // 标记为已感染}// 记录日志:显示感染传播路径log.info("-------------------");log.info("感染节点:{}, 被感染节点:{}", current, next);}}}// 统计需要核酸检测的人数(不包括初始确诊病例)int count = 0;for (int i = 0; i < n; i++) {// 创建final变量供Lambda表达式使用(Lambda要求外部变量为final或effectively final)int finalI = i;/*** 判断条件:* 1. visited[i]:该人员被标记为需要检测(通过接触传播被感染)* 2. Arrays.stream(confirmedCases).noneMatch(caseId -> caseId == finalI):* 使用Stream API检查该人员不在初始确诊病例数组中* 即:统计的是被传播感染的人员,不包括最初的感染者*/if (visited[i] && Arrays.stream(confirmedCases).noneMatch(caseId -> caseId == finalI)) {count++; // 符合条件的人员计数加1}}// 返回需要进行核酸检测的人数return count;}
}