华为OD机试中的“电脑病毒感染”题目是一个典型的图论问题,涉及到网络中的电脑如何通过连接传播病毒,并计算感染所有电脑所需的最短时间。以下是对该题目的详细解析:
一、题目描述
一个局域网内有很多台电脑,分别标注为0~N-1的数字。相连接的电脑距离不一样,所以感染时间不一样,感染时间用t表示。其中网络内一台电脑被病毒感染,求其感染网络内所有的电脑最少需要多长时间。如果最后有电脑不会感染,则返回-1。给定一个数组times表示一台电脑把相邻电脑感染所用的时间。path[i]={i, j, t}表示:电脑i->j,电脑i上的病毒感染j,需要时间t。
二、输入描述
4
3
2 1 1
2 3 1
3 4 1
2
三、输出描述
2
补充说明:
第一个参数:局域网内电脑个数N 1<=N<=200:
第二个参数:总共多少条网络连接
第三个121表示1->2时间为1
第七行:表示病毒最开始所在的电脑号1.
示例1
输入:
4
3
2 1 1
2 3 1
3 4 1
2
输出:
2
四、代码实现
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;public class ComputerVirusInfection {/*** 计算信号从源节点K传播到所有节点的最短时间* 如果无法传播到所有节点,返回-1* 使用Dijkstra算法找到从源节点到图中所有其他节点的最短路径** @param times 表示图中节点之间的传播时间,每个元素为一个数组,其中包含两个节点和它们之间的传播时间* @param N 表示图中节点的总数* @param K 表示源节点的编号* @return 返回信号传播到所有节点所需的最短时间,如果无法传播到所有节点则返回-1*/public static int networkDelayTime(int[][] times, int N, int K) {// 构建图的邻接表Map<Integer, List<int[]>> graph = new HashMap<>();for (int[] time : times) {graph.computeIfAbsent(time[0], k -> new ArrayList<>()).add(new int[]{time[1], time[2]});}// 优先队列,按感染时间从小到大排序PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));pq.offer(new int[]{K, 0});// 记录每个节点的最短感染时间Map<Integer, Integer> dist = new HashMap<>();dist.put(K, 0);while (!pq.isEmpty()) {int[] current = pq.poll();int node = current[0];int time = current[1];if (graph.containsKey(node)) {for (int[] neighbor : graph.get(node)) {int nextNode = neighbor[0];int nextTime = neighbor[1] + time;if (!dist.containsKey(nextNode) || nextTime < dist.get(nextNode)) {dist.put(nextNode, nextTime);pq.offer(new int[]{nextNode, nextTime});}}}}// 检查是否有未感染的电脑if (dist.size() != N) {return -1;}// 找出最长的感染时间int maxTime = 0;for (int time : dist.values()) {maxTime = Math.max(maxTime, time);}return maxTime;}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int N = scanner.nextInt(); // 电脑个数int M = scanner.nextInt(); // 连接数int[][] times = new int[M][3];for (int i = 0; i < M; i++) {times[i][0] = scanner.nextInt();times[i][1] = scanner.nextInt();times[i][2] = scanner.nextInt();}int K = scanner.nextInt(); // 病毒开始的电脑号int result = networkDelayTime(times, N, K);System.out.println(result);}
}
五、解题思路
-
理解问题:
- 我们有一个由N台电脑组成的局域网,这些电脑之间通过一些连接相互通信。
- 每条连接都有一个特定的传播时间,表示病毒从一个电脑传播到另一个电脑所需的时间。
- 给定一个起始电脑K,我们需要计算病毒传播到所有电脑所需的最短时间。
- 如果存在无法被感染的电脑,则返回-1。
-
构建图的表示:
- 使用邻接表来表示图,其中每个节点(电脑)都关联一个列表,该列表包含与该节点直接相连的其他节点以及它们之间的传播时间。
- 遍历输入的连接信息
times
,将每条连接添加到相应的节点列表中。
-
选择算法:
- 由于我们需要找到从起始节点到所有其他节点的最短路径,我们可以使用Dijkstra算法。
- Dijkstra算法适用于加权图,并且可以找到从单个源节点到所有其他节点的最短路径。
-
实现Dijkstra算法:
- 使用一个优先队列(最小堆)来存储待处理的节点,队列中的元素按照当前已知的最短路径长度进行排序。
- 初始化队列,将起始节点K及其到自身的距离为0加入队列。
- 使用一个哈希表
dist
来记录从起始节点到每个节点的最短路径长度。 - 不断从队列中取出当前最短路径的节点,并更新其邻居节点的最短路径长度(如果通过当前节点可以得到更短的路径)。
- 将更新后的邻居节点及其新的最短路径长度加入队列。
-
检查是否所有节点都被感染:
- 在完成Dijkstra算法后,检查
dist
哈希表的大小是否等于N(即图中节点的总数)。 - 如果
dist
的大小小于N,说明存在无法被感染的节点,返回-1。
- 在完成Dijkstra算法后,检查
-
计算最长感染时间:
- 遍历
dist
哈希表,找到最长的感染时间(即从起始节点到最远节点的最短路径长度)。 - 返回这个最长感染时间作为结果。
- 遍历
-
处理输入和输出:
- 从标准输入读取N(电脑个数)、M(连接数)、连接信息
times
以及起始节点K。 - 调用
networkDelayTime
函数计算最短感染时间。 - 将结果输出到标准输出。
- 从标准输入读取N(电脑个数)、M(连接数)、连接信息
通过以上步骤,我们可以解决给定的问题,并计算出病毒传播到所有电脑所需的最短时间(如果存在无法被感染的电脑,则返回-1)。
六、运行示例解析
输入
3
2 1 1
2 3 1
3 4 1
2
解析步骤
1.读取输入数据:
- N = 3:表示图中有3个节点。
- M = 3:表示有3条边。
- 边的数据:
- 2 1 1:表示从节点2到节点1的传播时间为1。
- 2 3 1:表示从节点2到节点3的传播时间为1。
- 3 4 1:表示从节点3到节点4的传播时间为1。
- K = 2:表示病毒从节点2开始传播。
2.构建图的邻接表: - graph 的结构如下:
{2: [[1, 1], [3, 1]],3: [[4, 1]]}
3.初始化优先队列和距离表:
- 优先队列 pq 初始状态:[[2, 0]],表示从节点2开始,初始时间为0。
- 距离表 dist 初始状态:{2: 0},表示节点2的最短感染时间为0。
4.Dijkstra算法执行过程: - 第一次迭代:
- 从优先队列中取出 [2, 0]。
- 更新邻居节点1和3的距离:
- 节点1:dist[1] = 1,加入优先队列 [[1, 1]]。
- 节点3:dist[3] = 1,加入优先队列 [[1, 1], [3, 1]]。
- 第二次迭代:
- 从优先队列中取出 [1, 1]。
- 节点1没有邻居,跳过。
- 第三次迭代:
- 从优先队列中取出 [3, 1]。
- 更新邻居节点4的距离:
- 节点4:dist[4] = 2,加入优先队列 [[4, 2]]。
- 第四次迭代:
- 从优先队列中取出 [4, 2]。
- 节点4没有邻居,跳过。
5.检查所有节点是否都被感染:
- dist 的最终状态:{2: 0, 1: 1, 3: 1, 4: 2}。
- dist.size() == 4,表示所有节点都被感染。
6.找出最长的感染时间:
- 最长的感染时间 maxTime = 2。
输出
2
总结
该程序使用Dijkstra算法计算从源节点K传播到所有节点的最短时间。
输入数据表示图的结构和源节点,输出是最长的传播时间。
在这个示例中,从节点2开始,信号传播到所有节点的最短时间为2。