当前位置:  首页>> 技术小册>> 数据结构与算法(中)

难度:
Hard

题意:

  1. 给定一张图,图上有无向边,边上有等距的点
  2. 从0出发,最长路径能够访问M个点,问总共能访问多少个点

思路:

  • 这个题是最短路的变种
  • 边上面点的个数就是边的权值,先做一遍最短路
  • 扫描每个边,判断左右两个端点的值,进行累加
    • 左/右 端点大于M的,不累加
    • 左/右 端点分别向边里面访问点,假设左端点能访问a个点,右端点能访问b个点,那么能访问的点数就是min(a + b, 该边点数)
  • 统计完边,再统计点,只需要扫描所有点,根据最短路的端点值,判断是否不大于M,累加
  • 最短路复杂度是o(n^2),最短路中间有一个步骤,每一轮寻找当前最小的点开扩展,这一步骤是可以用一个堆来优化,复杂度是o(n log e),e是边的个数。这个做法留给大家做练习

代码:

  1. class Solution {
  2. private static int MAX = 2000000000;
  3. private class Edge {
  4. int src;
  5. int dest;
  6. int value;
  7. public Edge(int src, int dest, int value) {
  8. this.src = src;
  9. this.dest = dest;
  10. this.value = value;
  11. }
  12. }
  13. public int reachableNodes(int[][] edges, int M, int N) {
  14. List<Edge>[] edgeList = new List[N];
  15. for (int i = 0;i < edgeList.length;i++) {
  16. edgeList[i] = new ArrayList<Edge>();
  17. }
  18. for (int i = 0;i < edges.length;i++) {
  19. edgeList[edges[i][0]].add(new Edge(edges[i][0], edges[i][1], edges[i][2] + 1));
  20. edgeList[edges[i][1]].add(new Edge(edges[i][1], edges[i][0], edges[i][2] + 1));
  21. }
  22. int ret = 0;
  23. boolean[] flag = new boolean[N];
  24. int[] min = new int[N];
  25. for (int i = 0;i < N;i++) {
  26. flag[i] = false;
  27. min[i] = MAX;
  28. }
  29. min[0] = 0;
  30. while (true) {
  31. int idx = -1;
  32. for (int i = 0;i < N;i++) {
  33. if (!flag[i] && min[i] != MAX) {
  34. if (idx == -1 || min[i] < min[idx]) {
  35. idx = i;
  36. }
  37. }
  38. }
  39. if (idx == -1) {
  40. break;
  41. }
  42. flag[idx] = true;
  43. for (int i = 0;i < edgeList[idx].size();i++) {
  44. Edge edge = edgeList[idx].get(i);
  45. if (!flag[edge.dest]) {
  46. min[edge.dest] = Math.min(min[edge.dest], min[edge.src] + edge.value);
  47. }
  48. }
  49. }
  50. for (int i = 0;i < edges.length;i++) {
  51. if (min[edges[i][0]] + edges[i][2] <= M || min[edges[i][1]] + edges[i][2] <= M) {
  52. ret += edges[i][2];
  53. continue;
  54. }
  55. int left = 0, right = 0;
  56. if (min[edges[i][0]] <= M) {
  57. left = M - min[edges[i][0]];
  58. }
  59. if (min[edges[i][1]] <= M) {
  60. right = M - min[edges[i][1]];
  61. }
  62. if (left + right >= edges[i][2]) {
  63. ret += edges[i][2];
  64. } else {
  65. ret += left + right;
  66. }
  67. }
  68. for (int i = 0;i < N;i++) {
  69. if (min[i] <= M) {
  70. ret++;
  71. }
  72. }
  73. return ret;
  74. }
  75. }

该分类下的相关小册推荐: