zoukankan      html  css  js  c++  java
  • 743. Network Delay Time

    There are N network nodes, labelled 1 to N.

    Given times, a list of travel times as directed edges times[i] = (u, v, w), where u is the source node, v is the target node, and w is the time it takes for a signal to travel from source to target.

    Now, we send a signal from a certain node K. How long will it take for all nodes to receive the signal? If it is impossible, return -1.

    Example 1:

    Input: times = [[2,1,1],[2,3,1],[3,4,1]], N = 4, K = 2
    Output: 2
    

    Note:

    1. N will be in the range [1, 100].
    2. K will be in the range [1, N].
    3. The length of times will be in the range [1, 6000].
    4. All edges times[i] = (u, v, w) will have 1 <= u, v <= N and 0 <= w <= 100.
    class Solution {
    public int networkDelayTime(int[][] times, int N, int K) {
        double[][] disTo = new double[N][N];
        for (int i = 0; i < N; i++) {
            Arrays.fill(disTo[i], Double.POSITIVE_INFINITY);
        }
        for (int i = 0; i < N; i++) {
            disTo[i][i] = 0;
        }
        for (int[] edge: times) {
            disTo[edge[0] - 1][edge[1] - 1] = edge[2];
        }
        for (int k = 0; k < N; k++) {
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    if (disTo[i][j] > disTo[i][k] + disTo[k][j])
                        disTo[i][j] = disTo[i][k] + disTo[k][j];
                }
            }
        }
        double max = Double.MIN_VALUE;
        for (int i = 0; i < N; i++) {
            if (disTo[K - 1][i] == Double.POSITIVE_INFINITY) return -1;//如果有一个节点从k到不了,就说明无法完成任务返回-1
            max = Math.max(max, disTo[K - 1][i]);
        }
        return (int) max;
    }
    }

    小改一下

    class Solution {
    public int networkDelayTime(int[][] times, int N, int K) {
        int[][] disTo = new int[N][N];
        for (int i = 0; i < N; i++) {
            Arrays.fill(disTo[i], 100000);
        }
        for (int i = 0; i < N; i++) {
            disTo[i][i] = 0;
        }
        for (int[] edge: times) {
            disTo[edge[0] - 1][edge[1] - 1] = edge[2];
        }
        for (int k = 0; k < N; k++) {
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    if (disTo[i][j] > disTo[i][k] + disTo[k][j])
                        disTo[i][j] = disTo[i][k] + disTo[k][j];
                }
            }
        }
        int max = -100000;
        for (int i = 0; i < N; i++) {
            if (disTo[K - 1][i] == 100000) return -1;
            max = Math.max(max, disTo[K - 1][i]);
        }
        return max;
    }
    }

    1. floyd-warshall

    初始化的时候i==j置0,表示没有走动

    先把最终矩阵求出来,意思是从i到j的最短路径,

    这道题最终转化成从节点k开始,最多要花多少步才能传播到所有节点,所以是上面的矩阵中取大值。

    比如从2出发,到1要一步,到4要二步,答案就是2.

    class Solution {
      public int networkDelayTime(int[][] times, int N, int K) {
            int[] dist = new int[N + 1];
            Arrays.fill(dist, Integer.MAX_VALUE);
            dist[K] = 0;
            for(int i = 1; i < N; i++) { // relax edges repeatedly, connecting relaxed source nodes
                int[] temp= Arrays.copyOf(dist,N+1);
                for(int[] e : times) { // traverse edge list
                    int u = e[0], v = e[1], w = e[2];
                    if (dist[u] != Integer.MAX_VALUE && dist[v] > temp[u] + w) { // connect newest reachable source
                        temp[v] = dist[u] + w;
                    }
                }
                dist = temp;
            }
            int maxwait = 0;
            for(int i=1; i <= N; i++) maxwait = Math.max(maxwait, dist[i]);
            return maxwait == Integer.MAX_VALUE ? -1 : maxwait;
        }
    }

     1

    2. Bellman Ford

    初始化dist[k] == 0, 其余为Integer.MAX_VALUE,转移方程是dist[v] = min[dist[v], dist[u] + w(u, v)]

    有N个节点外循环就有N-1次。

     意义:初始时除了自己外所有的dist【】置最大值,然后总共松弛N-1次,每一次遍历所有edge,

    if (dist[u] != Integer.MAX_VALUE && dist[v] > dist[u] + w)

    这个前面不等于极大值是要从出发点开始判断的意思,如果是极大值就说明这个点还到不了,就更没有办法经过uv到下一个点了。

    整个算法一直在维护和update一个dist【】数组,意思是从指定点到另外一个点v的距离,dist[u]是当前能到达的点, dist[v]是edge UV的终点,如果dist[v]大,就更新成指定点经过uv到达v的值

    https://www.youtube.com/watch?v=obWXjtg0L64

    3. Dijistra algorithm

    
    
    class Solution {
        public int networkDelayTime(int[][] times, int N, int K) {
            Map<Integer, Map<Integer,Integer>> map = new HashMap<>();//from, <to, distance>
            for(int[] time : times){
                map.putIfAbsent(time[0], new HashMap<>());
                map.get(time[0]).put(time[1], time[2]);
            }
            
            //离K的距离,节点
            Queue<int[]> pq = new PriorityQueue<>((a,b) -> (a[0] - b[0]));//用pq是为了每次获得和K距离最短的节点
            
            pq.offer(new int[]{0, K});
            
            boolean[] visited = new boolean[N+1];//每次把没有松弛的节点拿出来,松弛后更新
            int res = 0;
            
            while(!pq.isEmpty()){
                int[] cur = pq.poll();
                int curNode = cur[1];
                int curDist = cur[0];
                if(visited[curNode]) continue;
                visited[curNode] = true;
                res = curDist;
                N--;
                if(N == 0) return res;//所有节点都考虑完了
                if(map.containsKey(curNode)){//因为是单向图所以先考虑一下存不存在
                    for(int next : map.get(curNode).keySet()){
                        pq.add(new int[]{curDist + map.get(curNode).get(next), next});
                    }
                }
            }
            return N == 0 ? res : -1;
                
        }
    }
    
    
    
     

    算法的基本思想是:每次找到离源点(上面例子的源点就是 1 号顶点)最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。基本步骤如下:

    • 将所有的顶点分为两部分:已知最短路程的顶点集合 P 和未知最短路径的顶点集合 Q。最开始,已知最短路径的顶点集合 P 中只有源点一个顶点。我们这里用一个 book[ i ]数组来记录哪些点在集合 P 中。例如对于某个顶点 i,如果 book[ i ]为 1 则表示这个顶点在集合 P 中,如果 book[ i ]为 0 则表示这个顶点在集合 Q 中。
    • 设置源点 s 到自己的最短路径为 0 即 dis=0。若存在源点有能直接到达的顶点 i,则把 dis[ i ]设为 e[s][ i ]。同时把所有其它(源点不能直接到达的)顶点的最短路径为设为 ∞。
    • 在集合 Q 的所有顶点中选择一个离源点 s 最近的顶点 u(即 dis[u]最小)加入到集合 P。并考察所有以点 u 为起点的边,对每一条边进行松弛操作。例如存在一条从 u 到 v 的边,那么可以通过将边 u->v 添加到尾部来拓展一条从 s 到 v 的路径,这条路径的长度是 dis[u]+e[u][v]。如果这个值比目前已知的 dis[v]的值要小,我们可以用新值来替代当前 dis[v]中的值。
    • 重复第 3 步,如果集合 Q 为空,算法结束。最终 dis 数组中的值就是源点到所有顶点的最短路径。

    以上摘自https://wiki.jikexueyuan.com/project/easy-learn-algorithm/dijkstra.html

  • 相关阅读:
    【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理
    【bzoj4832】[Lydsy1704月赛]抵制克苏恩 期望dp
    【bzoj3796】Mushroom追妹纸 hash/sa+kmp+二分
    【bzoj3309】DZY Loves Math 莫比乌斯反演+线性筛
    【bzoj2813】 奇妙的Fibonacci数列 线性筛
    面向对象实现简单的学生课程选择
    小案例--面向对象中实现分页
    初识面向对象四(装饰器/反射)
    python小技巧--控制台输出带颜色的文字方法
    初识面向对象三(经典类/多态/鸭子类型/初识封装)
  • 原文地址:https://www.cnblogs.com/wentiliangkaihua/p/12244695.html
Copyright © 2011-2022 走看看