leetcode刷题记录-743. 网络延迟时间-floyd 弗洛伊德算法

352 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

今天日常打开leetcode,困难,看几遍题目,ok,看不懂,cv睡大觉。。。

今天的每日一题对于我来说难度略大,但是可以来看一些大佬推荐的同等类型的中等题--【短路/必背模板】涵盖所有的「存图方式」与「最短路算法(详尽注释)」。

每日一题

所以今天的每日一题为743. 网络延迟时间,难度为中等

  • 有 n 个网络节点,标记为 1 到 n。

  • 给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。

  • 现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。

示例 1:

输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2

示例 2:

输入:times = [[1,2,1]], n = 2, k = 1
输出:1

示例 3:

输入:times = [[1,2,1]], n = 2, k = 2
输出:-1

 

提示:

  • 1 <= k <= n <= 100
  • 1 <= times.length <= 6000
  • times[i].length == 3
  • 1 <= ui, vi <= n
  • ui != vi
  • 0 <= wi <= 100
  • 所有 (ui, vi) 对都 互不相同(即,不含重复边)

题解

再开始做题之前,我们先来了解一下,题目中的这种图的数据格式,我们应该怎么去存下来。

  • 邻接矩阵

  • 通过二维数组对应一个值的方式来定义每两个点他们相对应的值。

// 邻接矩阵数组:w[a][b] = c 代表从 ab 有权重为 c 的边
let arr = [][]
// 加边操作
void add(int a, int b, int c) {
    arr[a][b] = c;
}

像上面这个数据结构,就是定义两边之间的值,比如说,传入arr[a][b] = c,就是点a到点b的路径长为c。

floyd 弗洛伊德算法

首先由前面的定义,我们能够得到任意两点之间的距离,但是,有一种可能性,就是任意两点之间的距离并不是最近的,比如说:

image.png 那么a到c的最短距离就不是6而是通过b做一个中转后的2+3=5了。

由上我们可以看出,要计算两个点之间的最小距离,不能只是直接考虑,还要考虑中转的方式,就是说要判断一下arr[a][b]+arr[b][c]和arr[a][c]之间大小。

在进一步扩展,就是我们计算每一条边之前,都要接入第三个中转点来判断它们之间距离的大小,所以我们就可以得出一个三重循环来判断我们每一条边之间的最小距离:

function floyd(arr, n) {
    // 使用中间节点k,松弛i->j的距离
    for (let k = 0; k < n; k++) {
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < n; j++) {
                arr[i][j] = Math.min(map[i][j], map[i][k] + map[k][j]);
            }
        }
    }
}

这就是弗洛伊德算法,通过三次循环并且引入中间结点,来为每一条边添加判断。

这样,结合上面的算法我们能够得出每个结点之间的最小距离,在通过上面的双重数组构建一个对于图之间结点距离的描述。同时求的是从k点出发,所有点都被访问到的最短时间,将问题转换一下其实就是求从k点出发,到其他点的最短距离的最大值」。我们就能够通过floyd得出我们想要的结果了。

/**
 * @param {number[][]} times
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var networkDelayTime = function (times, n, k) {
    const arr = Array.from({ length: n }, () => new Array(n).fill(Infinity));
    for (let i = 0; i < n; i++) arr[i][i] = 0;
    for (const [f, t, w] of times) arr[f - 1][t - 1] = w

    floyd(arr, n)

    const ans = Math.max(...arr[k -1]);
    return ans === Infinity ? -1 : ans;
};
/**
 * @param {number[][]} arr 生成的图
 * @param {number} n 结点个数
 */
function floyd(arr, n) {
    // 使用中间节点k,松弛i->j的距离
    for (let k = 0; k < n; k++) {
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < n; j++) {
                arr[i][j] = Math.min(arr[i][j], arr[i][k] + arr[k][j]);
            }
        }
    }
}

image.png