IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Floyd算法 Java实现 -> 正文阅读

[数据结构与算法]Floyd算法 Java实现

算法导入

在上一篇博客中,咱讲述了求单源最短路径的一种经典算法 Dijkstra 算法,想了解的同学可以走前门瞅一瞅,记得回来哈。

经典Dijkstra算法 Java实现

但是因为算法的局限性,一是不能处理非负权图,二是只能处理单源到其他点的最短路径。有些小伙伴肯定不满意了呀!别急,今天咱介绍另一种的算法,Floyd算法,而且实现极其简单,for就完事了。先上图,咱梳理一下最短路中各种算法的差异。

请添加图片描述

算法核心

Floyd算法的核心思想为动态规划,动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题。最简单的动态规划,斐波纳契数列,也叫兔子数列(兔子繁殖例子)1,1,2,3,5,8,13,21…

对于上面的数列,我们可以首先确定边界条件是 F(0) = 1, F(1) = 1, 当 n >= 2时,F(n) = F(n - 1) + F(n-2)。当转移方程确定后,就能够方便的求出后者了。

那么在Floyd算法中,定义一个数组 f[k][x][y] 表示 只允许经过 结点1到 k,结点 x到 y的最短路径长度,也就是说,当 k = 6 时,可能 x - 1 - y 最短,也可能 x - 2 - 5 - 3 - y 最短,在满足条件下,f[k][x][y] = min(最短路径)。假设有n个结点,编号1 - n,那么可以确定:

  • f[n][x][y]:结点 x 到 y 的最短路径。
  • f[0][x][y]:不经过任何结点,x -> y 的最短路径。若两者直接相连,x -> y = w(x, y) 最短路径为权值,或者两者不直接相连,为正无穷

确定边界条件之后,我们来确定转移方程,对于任何一个f[k][x][y], 有两种到达方式:

  1. 不经过k 个结点,那么 f[k][x][y] = f[k - 1][x][y];
  2. 经过k 个结点了,那么 f[k][x][y] = f[k - 1][x][k] + f[k - 1][k][y]
  3. 两者取最小值。

那么最终的转移方程即可确定 f[k][x][y] = min(f[k-1][x][y], f[k-1][x][k] + f[k-1][k][y] )

可以看到 如果顺序求值,第一维对结果并没有影响,那么可以转变为:f[x][y] = min(f[x][y], f[x][k] + f[k][y])

转移方程有了,边界条件有了,那么代码就水到渠成了。

代码实现

import java.util.*;

/**
 * @author LKQ
 * @date 2022/4/21 18:52
 * @description Floyd算法,适用于任何图,且不管有向无向,边权正负。但是最短路必须存在
 * 时间复杂度为O(n^3),适用于稠密图,即 m(边的数量)  约等于 n^2 (点的数量)
 */
public class Solution {
    /**
     * 邻接矩阵存储
     */
    int[][] graph;

    int INF = Integer.MAX_VALUE / 2;
    /**
     * 多源最短路算法
     * @param n n个结点 编号 0 - n-1
     * @param edges 边 e[0] - e[1] 的权值为 e[2]
     */
    public void floyd(int n, int[][] edges) {
        // 1. 初始化邻接矩阵
        graph = new int[n][n];
        for (int i = 0; i < n; i++) {
            // 点到其他点的距离为无穷大
            Arrays.fill(graph[i], INF);
            // 点到自身的距离为0
            graph[i][i] = 0;
        }
        // 注意有向图和无向图的区别,无向图 u -> v,v -> u 都要设置,有向图 只要设置 u -> v
        for(int[] e: edges) {
            graph[e[0]][e[1]] = e[2];
            graph[e[1]][e[0]] = e[2];
        }
        // floyd 基本流程为三层循环:
        // 枚举中转点 - 枚举起点 - 枚举终点 - 松弛操作
        for (int k = 0; k < n; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    graph[i][j] = Math.min(graph[i][j], graph[i][k] + graph[k][j]);
                }
            }
        }
    }
}

核心代码只有三个for循环,是不是很简单

没骗你们吧。但是要注意一点,由于时间复杂度为 O(n^3),而且空间复杂度 为 O(n ^ 2),当点较多时,那么就有可能造成 TLE 或 MLE ,做题目的时候尤其需要小心。

参考资料

OI Wiki
图灵程序设计丛书 算法 第4版

结尾

琅琅书声如春风,拂过千年时空
少年啊壮志在胸, 赋首词让人感动
许嵩 / 孙涛 《书香年华》

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 12:01:52  更:2022-04-26 12:06:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:43:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码