|
| 1 | +### 899. Reachable Nodes In Subdivided Graph |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +题目: |
| 6 | +https://leetcode.com/problems/reachable-nodes-in-subdivided-graph/ |
| 7 | + |
| 8 | +难度: |
| 9 | +Hard |
| 10 | + |
| 11 | +题意: |
| 12 | + |
| 13 | +1. 给定一张图,图上有无向边,边上有等距的点 |
| 14 | +2. 从0出发,最长路径能够访问M个点,问总共能访问多少个点 |
| 15 | + |
| 16 | +思路: |
| 17 | + |
| 18 | +- 这个题是最短路的变种 |
| 19 | +- 边上面点的个数就是边的权值,先做一遍最短路 |
| 20 | +- 扫描每个边,判断左右两个端点的值,进行累加 |
| 21 | + - 左/右 端点大于M的,不累加 |
| 22 | + - 左/右 端点分别向边里面访问点,假设左端点能访问a个点,右端点能访问b个点,那么能访问的点数就是min(a + b, 该边点数) |
| 23 | +- 统计完边,再统计点,只需要扫描所有点,根据最短路的端点值,判断是否不大于M,累加 |
| 24 | +- 最短路复杂度是o(n^2),最短路中间有一个步骤,每一轮寻找当前最小的点开扩展,这一步骤是可以用一个堆来优化,复杂度是o(n log e),e是边的个数。这个做法留给大家做练习 |
| 25 | + |
| 26 | +代码: |
| 27 | + |
| 28 | +```java |
| 29 | +class Solution { |
| 30 | + private static int MAX = 2000000000; |
| 31 | + |
| 32 | + private class Edge { |
| 33 | + int src; |
| 34 | + int dest; |
| 35 | + int value; |
| 36 | + |
| 37 | + public Edge(int src, int dest, int value) { |
| 38 | + this.src = src; |
| 39 | + this.dest = dest; |
| 40 | + this.value = value; |
| 41 | + } |
| 42 | + } |
| 43 | + |
| 44 | + public int reachableNodes(int[][] edges, int M, int N) { |
| 45 | + List<Edge>[] edgeList = new List[N]; |
| 46 | + for (int i = 0;i < edgeList.length;i++) { |
| 47 | + edgeList[i] = new ArrayList<Edge>(); |
| 48 | + } |
| 49 | + |
| 50 | + for (int i = 0;i < edges.length;i++) { |
| 51 | + edgeList[edges[i][0]].add(new Edge(edges[i][0], edges[i][1], edges[i][2] + 1)); |
| 52 | + edgeList[edges[i][1]].add(new Edge(edges[i][1], edges[i][0], edges[i][2] + 1)); |
| 53 | + } |
| 54 | + |
| 55 | + int ret = 0; |
| 56 | + |
| 57 | + boolean[] flag = new boolean[N]; |
| 58 | + int[] min = new int[N]; |
| 59 | + for (int i = 0;i < N;i++) { |
| 60 | + flag[i] = false; |
| 61 | + min[i] = MAX; |
| 62 | + } |
| 63 | + |
| 64 | + min[0] = 0; |
| 65 | + while (true) { |
| 66 | + int idx = -1; |
| 67 | + for (int i = 0;i < N;i++) { |
| 68 | + if (!flag[i] && min[i] != MAX) { |
| 69 | + if (idx == -1 || min[i] < min[idx]) { |
| 70 | + idx = i; |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + if (idx == -1) { |
| 75 | + break; |
| 76 | + } |
| 77 | + |
| 78 | + flag[idx] = true; |
| 79 | + for (int i = 0;i < edgeList[idx].size();i++) { |
| 80 | + Edge edge = edgeList[idx].get(i); |
| 81 | + if (!flag[edge.dest]) { |
| 82 | + min[edge.dest] = Math.min(min[edge.dest], min[edge.src] + edge.value); |
| 83 | + } |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + for (int i = 0;i < edges.length;i++) { |
| 88 | + if (min[edges[i][0]] + edges[i][2] <= M || min[edges[i][1]] + edges[i][2] <= M) { |
| 89 | + ret += edges[i][2]; |
| 90 | + continue; |
| 91 | + } |
| 92 | + int left = 0, right = 0; |
| 93 | + if (min[edges[i][0]] <= M) { |
| 94 | + left = M - min[edges[i][0]]; |
| 95 | + } |
| 96 | + if (min[edges[i][1]] <= M) { |
| 97 | + right = M - min[edges[i][1]]; |
| 98 | + } |
| 99 | + if (left + right >= edges[i][2]) { |
| 100 | + ret += edges[i][2]; |
| 101 | + } else { |
| 102 | + ret += left + right; |
| 103 | + } |
| 104 | + } |
| 105 | + |
| 106 | + for (int i = 0;i < N;i++) { |
| 107 | + if (min[i] <= M) { |
| 108 | + ret++; |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + return ret; |
| 113 | + } |
| 114 | +} |
| 115 | +``` |
| 116 | + |
0 commit comments