电脑病毒感染 - 华为OD统一考试

OD统一考试

题解: Java / Python / C++

alt

题目描述

一个局域网只内有很多台电脑,分别标注为 1 ~ N 的数字。相连接的电脑距离不一样,所以感染时间不一样,感染时间用t 表示。

其中网络内一台电脑被病毒感染,求其感染网络内所有的电脑最少需要多长时间。如果最后有电脑不会感染,则返回-1。

给定一个数组 times 表示一台电脑把相邻电脑感染所用的时间: path[i] = {i, j, t} 表示: 电脑i 上的病毒感染 j,需要时间 t 。

输入描述

第一行输入一个整数N,表示局域网内电脑个数 N,1<= N<= 200 ;

第二行输入一个整数M, 表示有 M 条网络连接;

接下来M行, 每行输入为 i,j,t 。表示电脑 i 感染电脑 j 需要时间t。(1 <= i, j <= N)

最后一行为病毒所在的电脑编号。

输出描述

输出最少需要多少时间才能感染全部电脑,如果不存在输出 -1

示例1

输入:
4
3
2 1 1
2 3 1
3 4 1
2

输出:
2

image-20231227122501319

示例2

输入:
4
3
2 1 1
2 3 1
3 4 1
3

输出:
-1

题解

经典的最短路径问题,使用 Dijkstra 算法求解。

代码思路:

1、 图的构建:使用 g 表示图,其中键为电脑编号,值为与该电脑相邻的电脑以及感染所需的时间。

2、优先队列:使用 heap 作为优先队列,队列中存储的是数组 {时间, 电脑编号}

3、Dijkstra 算法:开始时,将病毒所在电脑加入队列,并设置时间为0。然后,不断从队列中取出时间最小的电脑,将其相邻的未感染电脑加入队列,并更新感染时间。重复这个过程直到所有电脑都被感染或队列为空。

4、输出结果:根据感染情况输出结果。

Java

import java.util.*;
/**
 * @author code5bug
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt(), M = scanner.nextInt();

        // 构建图
        Map<Integer, List<int[]>> g = new HashMap<>();
        for (int i = 0; i < M; ++i) {
            int a = scanner.nextInt(), b = scanner.nextInt(), t = scanner.nextInt();
            g.computeIfAbsent(a, k -> new ArrayList<>()).add(new int[]{b, t});
        }

        // 病毒所在的编号, 优先级队列,已经感染的电脑集合
        int sid = scanner.nextInt();
        PriorityQueue<int[]> heap = new PriorityQueue<>(Comparator.comparingInt(arr -> arr[0]));
        Set<Integer> vis = new HashSet<>();

        heap.add(new int[]{0, sid});
        while (!heap.isEmpty()) {
            int[] arr = heap.poll();
            int time = arr[0], id = arr[1];
            vis.add(id);

            if (N == vis.size()) {  // 感染了所有电脑
                System.out.println(time);
                return;
            }

            for (int[] neighbor : g.getOrDefault(id, Collections.emptyList())) {
                int nextId = neighbor[0], costTime = neighbor[1];
                if (!vis.contains(nextId)) {  // 此时 nextId 电脑还没有被感染
                    heap.add(new int[]{time + costTime, nextId});
                }
            }
        }

        if (N != vis.size()) {
            System.out.println(-1);
        }
    }
}

Python

from collections import defaultdict
from heapq import heappop, heappush

N = int(input())
M = int(input())

# 构建图
g = defaultdict(set)
for _ in range(M):
    i, j, t = map(int, input().split())
    g[i].add((j, t))

# 病毒所在的编号, 优先级队列,已经感染的电脑集合
sid, heap, vis = int(input()), [], set()

heappush(heap, (0, sid))
while heap:
    time, id = heappop(heap)
    vis.add(id)

    if N == len(vis):  # 感染了所有电脑
        print(time)
        break

    for next_id, cost_time in g[id]:
        if next_id not in vis:  # 此时 next_id 电脑还没有被感染
            heappush(heap, (time + cost_time, next_id))

if N != len(vis):
    print(-1)

C++

#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>
using namespace std;

int main() {
    int N, M;
    cin >> N >> M;

    // 构建图
    unordered_map<int, vector<pair<int, int>>> g;
    for (int i = 0; i < M; ++i) {
        int a, b, t;
        cin >> a >> b >> t;
        g[a].push_back({b, t});
    }

    // 病毒所在的编号, 优先级队列,已经感染的电脑集合
    int sid;
    cin >> sid;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> heap;
    unordered_set<int> vis;

    heap.push({0, sid});
    while (!heap.empty()) {
        auto [time, id] = heap.top();
        heap.pop();
        vis.insert(id);

        if (N == vis.size()) {  // 感染了所有电脑
            cout << time << endl;
            return 0;
        }

        for (const auto& neighbor : g[id]) {
            int next_id = neighbor.first;
            int cost_time = neighbor.second;
            if (vis.find(next_id) == vis.end()) {  // 此时 next_id 电脑还没有被感染
                heap.push({time + cost_time, next_id});
            }
        }
    }

    if (N != vis.size()) {
        cout << -1 << endl;
    }

    return 0;
}

相关练习题

题号题目难易
LeetCode 743743. 网络延迟时间中等

🙏整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏