【华为OD】2024D卷——精准核酸检测

题目描述:
为了达到新冠疫情精准防控的需要,为了避免全员核酸检测带来的浪费,需要精准圈定可能被感染的人群。现在根据传染病流调以及大数据分析,
得到了每个人之间在时间、空间上是否存在轨迹的交叉。
现在给定一组确诊人员编号(X1,X2,X3....Xn),在所有人当中,找出哪些人需要进行核酸检测,输出需要进行核酸检测的人数。(注意:确诊病例自身不需要再做核酸检测)
需要进行核酸检测的人,是病毒传播链条上的所有人员,即有可能通过确诊病例所能传播到的所有人。
例如:A是确诊病例,A和B有接触、B和C有接触、C和D有接触、D和E有接触,那么B\C\D\E都是需要进行核酸检测的人。

输入描述:
第一行为总人数N
第二行为确诊病例人员编号(确诊病例人员数量 
  

解决思路:

1、输入解析:读取总人数 N、确诊病例编号列表、接触矩阵。

2、图的构建:将接触矩阵转换为图的邻接表表示。

3、图的遍历

      ·构造状态访问列表visited,visited[i] == 1 表示第i个需要核酸检测

      ·构造存储接触人员的列表need_test_people

      ·从每个确诊病例开始,使用DFS遍历图,找到所有与之连通的节点(接触人员)。

4、输出结果:统计所有需要做核酸检测(接触人员)的人数。


代码部分

def count_need_to_test(n, confirmed_cases, contact_relationship):
    #确诊病例转换为列表
    confirmed_cases_list = list(map(int, confirmed_cases.split(',')))
    #访问状态数组
    visited = [0] * n

    def dfs(case, visited):
        # 遍历当前人员与其他所有人的接触情况
        for neighbor in range(n):
            #存在接触人员,且该人员未曾被其他人接触时
            #当neighbor = case时,由于调用dfs函数前,已将visited[case]置为1,会直接跳过此判断,执行下一次循环
            if contact_relationship[case][neighbor] == 1 and not visited[neighbor]:
                visited[neighbor] = 1
                dfs(neighbor, visited)

    # 确诊病例标记为已访问
    for case in confirmed_cases_list:
        visited[case] = 1
        dfs(case, visited)

    #统计需要做检测的人数
    count = sum(visited) - len(confirmed_cases_list)        #visited中记为1的序号为全体需要做核酸的人(包括已确诊病人)
    all_test_people = [i for i in range(len(visited)) if visited[i] == 1]
    need_test_people = [i for i in all_test_people if i not in confirmed_cases_list]
    return count, need_test_people

n = int(input())
confirmed_cases = input()
contact_relationship = [list(map(int, input().strip().split(','))) for _ in range(n)]
num, people = count_need_to_test(n, confirmed_cases, contact_relationship)
print(num)

其他思路:

可以直接将visited等存储列表变更为set,使用set.add()操作将确诊病例的密接者加入集合。


代码部分:

def need_to_test(n, confirmed_cases, contact_relationship):
    confirmed_cases_set = set(map(int, confirmed_cases.split(',')))
    #使用集合确认不重复添加
    need_people = set()
    visited = set()

    def dfs(case, visited):
        for neighbor in range(n):
            if contact_relationship[case][neighbor] == 1 and neighbor not in visited:
                visited.add(neighbor)
                need_people.add(neighbor)
                dfs(neighbor, visited)
    #遍历每个确诊病例
    for case in confirmed_cases_set:
        visited.add(case)
        dfs(case, visited)
    #去除确诊病例自身
    need_people -= confirmed_cases_set        #集合可以直接使用-,表示集合差集 A-B = A-(A&B)      
    return len(need_people), need_people

知识点:图的遍历(DFS),列表

由于对BFS解法不太熟悉,若有高人也请指点一二


结语:越简单的题目解法应该越多,请路过大神留下新的思路供本小白学习一下,打开思路

你可能感兴趣的:(Python解应用题,华为od,python)