【OD机试题解法笔记】核算检测

题目


为了达到新冠疫情精准防控的需要,为了避免全员核酸检测带来的浪费,需要精准圈定可能被感染的人群。

现在根据传染病流调以及大数据分析,得到了每个人之间在时间、空间上是否存在轨迹的交叉。

现在给定一组确诊人员编号(X1,X2,X3...Xn) 在所有人当中,找出哪些人需要进行核酸检测,输出需要进行核酸检测的人数。(注意:确诊病例自身不需要再做核酸检测)

需要进行核酸检测的人,是病毒传播链条上的所有人员,即有可能通过确诊病例所能传播到的所有人。

例如:A是确诊病例,A和B有接触、B和C有接触,C和D有接触,D和E有接触。那么B、C、D、E都是需要进行核酸检测的。

输入描述
第一行为总人数N

第二行为确诊病例人员编号 (确证病例人员数量 < N) ,用逗号隔开

接下来N行,每一行有N个数字,用逗号隔开,其中第 i 行的第 j 个数字表示编号 i 是否与编号 j 接触过。0 表示没有接触,1 表示有接触

输出描述
输出需要做核酸检测的人数

补充说明
人员编号从0开始
0 < N < 100

用例

输入        输出说明
5
1,2
1,1,0,1,0
1,1,0,0,0
0,0,1,0,1
1,0,0,1,0
0,0,1,0,1
3编号为1、2号的人员为确诊病例1号与0号有接触,0号与3号有接触,2号4号有接触。所以,需要做核酸检测的人是0号、3号、4号,总计3人要进行核酸检测。

思考

图搜索问题,从干扰人员 id 开始递归深度优先搜索接触人员并累计结果计数。矩阵对角线上都是1,只需要搜索对角线一侧的矩阵就行,备忘录visited定义为一维数组根据人员id来标识是否已被访问。

算法过程

1、根据输入构建邻接矩阵,行列都是人员id,索引从0开始,mtx[rowIndex][colIndex] 表示人员rowIndex 与 人员 colIndex 是否接触(1:接触,0:未接触);

2、定义一维 visited 数组用以标记人员是否已被访问,初始化把感染人员标记为true,因为感染人员不加入核酸检测统计;

3、枚举感染人员id开始 dfs,遍历人员id,从0~N-1,排除自己,查询矩阵判断其它人员是否与感染人员接触且未访问,若是则统计结果+1,继续dfs (接触人员id),最终完成所有人员搜索返回统计结果。

参考代码

function solution(lines) {
    const arr = lines.trim().split('\n').map(line => line.trim().split(',').map(e => parseInt(e)));
    const n = arr[0][0];
    const sicks = arr[1];
    const mtx = arr.slice(2);
    const visited = new Array(n).fill(false); // 标记节点是否被访问
    
    // 将确诊人员标记为已访问(不参与检测)
    for (let s of sicks) {
        visited[s] = true;
    }
    
    let result = 0;
    
    // 从节点u开始DFS,遍历所有可达节点
    const dfs = function(u) {
        for (let v = 0; v < n; v++) {
            if (u === v) continue; // 跳过自身
            if (mtx[u][v] && !visited[v]) {
                visited[v] = true;
                result++;
                dfs(v); // 递归搜索相邻节点
            }
        }
    };
    
    // 从每个确诊人员出发进行DFS
    for (let s of sicks) {
        dfs(s);
    }
    
    return result;
}

let inputs = [
`5
1,2
1,1,0,1,0
1,1,0,0,0
0,0,1,0,1
1,0,0,1,0
0,0,1,0,1`,
`5  
0  
0,1,0,0,0  
1,0,0,0,0  
0,0,0,1,0  
0,0,1,0,1  
0,0,0,1,0`   
];

inputs.forEach(line => {
  console.log(solution(line));
});    

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值