Floyd(多源最短路径)

110 阅读2分钟

核心概念

  • 是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法
  • 解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。
  • 时间复杂度为O(N^3),空间复杂度为O(N^2)
  • 以每个点为「中转站」,刷新所有「入度」和「出度」的距离
  • 遍历每一个顶点 --> 遍历点的每一个入度 --> 遍历每一个点的出度

核心代码

//顶点从1开始计,总顶点数为n
for(k=1;k<=n;k++) //把每个顶点作为中转站,进行松弛操作
    for(i=1;i<=n;i++)//起始顶点
        for(j=1;j<=n;j++) //结束顶点
            if(d[i][k]+d[k][j]<d[i][j])
                d[i][j]=d[i][k]+d[k][j];

实战题目一

原题目地址:
leetcode.cn/problems/fi…

题目描述:
有 n 个城市,按从 0 到 n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold。

返回能通过某些路径到达其他城市数目最少、且路径距离 最大 为 distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 i 和 j 的路径的距离等于沿该路径的所有边的权重之和。

示例 1:
输入:n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]],distanceThreshold = 4
输出:3
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2]
城市 1 -> [城市 0, 城市 2, 城市 3] 
城市 2 -> [城市 0, 城市 1, 城市 3] 
城市 3 -> [城市 1, 城市 2] 
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。

示例 2:
输入:n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]],distanceThreshold = 2
输出:0
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是:
城市 0 -> [城市 1]
城市 1 -> [城市 0, 城市 4]
城市 2 -> [城市 3, 城市 4]
城市 3 -> [城市 2, 城市 4]
城市 4 -> [城市 1, 城市 2, 城市 3]
城市 0 在阈值距离 2 以内只有 1 个邻居城市。

提示:
2<=n<=1002 <= n <= 100
1<=edges.length<=n(n1)/21 <= edges.length <= n * (n - 1) / 2
edges[i].length==3edges[i].length == 3
0<=fromi<toi<n0 <= from_i < to_i < n
1<=weighti, distanceThreshold<=1041 <= weight_i, distanceThreshold <= 10^4
所有 (fromi,toi)(from_i, to_i) 都是不同的。

题目分析
使用邻接矩阵建图+Floyd算法处理最短距离

java实现

class Solution {
    public int findTheCity(int n, int[][] edges, int distanceThreshold) {
    int[][] e=new int[n][n];
    for(int i=0;i<e.length;i++)
        for(int j=0;j<e.length;j++){
            if(i==j) e[i][j]=0;
            else e[i][j]=Integer.MAX_VALUE/4; 
        }
    for(int[] c:edges){
        e[c[0]][c[1]]=c[2];
        e[c[1]][c[0]]=c[2];
    }
    f(e,n);
int min = 101,res = 0;
        for(int i = 0;i<n;i++){
            int cur = 0;
            for(int j = 0;j<n;j++){
                if(e[i][j]<=distanceThreshold){
                    cur++;
                }
            }
            if(cur<=min){
                min = cur;
                res = i;
            }
        }
        return res;
    }
    void f(int[][] e,int n){
        for(int k=0;k<n;k++)
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++){
                    if (i == j ) {
                        // 这些情况都不符合下一行的if条件,
                        // 单独拿出来只是为了防止两个INT_MAX相加导致溢出
                        continue;
                    }
                    e[i][j]=Math.min(e[i][j],e[i][k]+e[k][j]);
                }
        return;
    } 
}