一、题目 §
题目:
一个局域网内有很多台电脑,分别标注为 0 \~ N-1 的数字。相连接的电脑距离不一样,所以感染时间不一样,感染时间用 t 表示。
其中网络内一台电脑被病毒感染,求其感染网络内所有的电脑最少需要多长时间。如果最后有电脑不会感染,则返回-1。
给定一个数组 times 表示一台电脑把相邻电脑感染所用的时间。如:path[i] = {i, j, t} 表示:电脑 i->j,电脑 i 上的病毒感染 j,需要时间 t。
输入:
第一个参数:局域网内电脑个数N,1 ≤ N ≤ 200;
第二个参数:总共多少条网络连接
第三个 2 1 1 表示2->1时间为1
第六行:表示病毒最开始所在电脑号2
输出:
感染网络内所有的电脑最少需要多长时间
示例:
输入:
4
3
2 1 1
2 3 1
3 4 1
2
输出:
2
二、题解 §
- 使用迪杰斯特拉算法(Dijkstra)求加权图中找从源点到目标点之间的最短路径。本题需要求从源点到所有其他节点的最短路径,取最大的就是遍历所有节点的最小路径
- 本解法没有考虑有向图有环
package org.stone.study.algo.ex202411;
import java.util.*;
public class VirusInfectTime {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 4
int n = Integer.parseInt(scanner.nextLine());
// 3
int m = Integer.parseInt(scanner.nextLine());
int[][] conn = new int[m][3];
// 2 1 1
// 2 3 1
// 3 4 2
for(int i = 0; i < m; i++) {
conn[i] = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
}
// 2
int src = scanner.nextInt();
int ans = getMinInfectTime(n, m, conn, src);
// 3
System.out.println(ans);
}
/**
* djikstra 算法找到遍历有向图全部节点最短路径。不能遍历全部节点时返回-1;能遍历全部时找花费时间最长的节点就是图全部遍历的最小时间
* 没有考虑有环的有向图
* @param n
* @param m
* @param conn
* @param src
* @return
*/
private static int getMinInfectTime(int n, int m, int[][] conn, int src) {
// 构建有向图的邻接表
Map<Integer, List<int[]>> graph = new HashMap<>();
for(int[] edge : conn) {
int u = edge[0];
int v = edge[1];
int w = edge[2];
graph.computeIfAbsent(u, k -> new ArrayList<>()).add(new int[]{v, w});
}
// dijkstra 算法找到最短路径
PriorityQueue<int[]> queue = new PriorityQueue<>(Comparator.comparingInt(e -> e[0]));
int[] dist = new int[n + 1];
Arrays.fill(dist, Integer.MAX_VALUE);
queue.add(new int[]{0, src});
dist[src] = 0;
while(!queue.isEmpty()) {
int[] cur = queue.poll();
int curTime = cur[0];
int curNode = cur[1];
// 剪枝:其他路径可能修改过最短距离
if(curTime > dist[curNode]) {
continue;
}
for(int[] next : graph.getOrDefault(curNode, Collections.emptyList())) {
int nextNode = next[0];
int nextTime = next[1];
if(curTime + nextTime < dist[nextNode]) {
dist[nextNode] = curTime + nextTime;
queue.add(new int[]{dist[nextNode], nextNode});
}
}
}
// 找到最长的最短路径,如果有节点未遍历到返回-1
int ans = 0;
for(int i = 1; i <= n; i++) {
if(dist[i] == Integer.MAX_VALUE) {
return -1;
}
ans = Math.max(ans, dist[i]);
}
return ans;
}
}