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

原文地址:https://www.cnblogs.com/wentiliangkaihua/p/12244695.html