Floyd 算法

目录

一、基础介绍

二、核心思想

三、核心例题

1、引出为何用动态规划:

2、算法:

[3、确定dp数组(dp table)以及下标的含义:](#3、确定dp数组(dp table)以及下标的含义:)

4、确定递推公式:

5、dp数组如何初始化:


一、基础介绍

首相简单的说一下,Floyed算法 又称Floyd-Warshall算法,是为了纪念罗伯特•弗洛伊德(Robert W.Floyd)。所以不要对这个奇怪的名字感到吃力。

Floyd算法 是一种在具有正或负边缘权重(但没有负周期)的加权图 中找到最短路径 的算法。并且,它不同与Dijkstra、Bellman-Ford这种单源最短路径问题(即只能有一个起点)。而Floyed算法是多源最短路径问题,即 求多个起点到多个终点的多条最短路径。

二、核心思想

Floyd算法其核心思想是运用动态规划,通过一个图的权值矩阵求出它的每两点间的最短路径矩阵。其时间与空间复杂度如下:

时间复杂度:O(n^3)

空间复杂度:O(n^2)

简而言之,Floyed算法 就是一种容易理解 ,可以算出任意两个节点之间的最短距离,代码编写简单的算法 。缺点就是时间复杂度比较高,不适合计算大量数据。

当然只是知道概念其实没那么重要,我从代码随线录中截取一个例题,相信通过这道题,大家定能受益匪浅。

三、核心例题


卡码网:97. 小明逛公园

【题目描述】

小明喜欢去公园散步,公园内布置了许多的景点,相互之间通过小路连接,小明希望在观看景点的同时,能够节省体力,走最短的路径。

给定一个公园景点图,图中有 N 个景点(编号为 1 到 N),以及 M 条双向道路连接着这些景点。每条道路上行走的距离都是已知的。

小明有 Q 个观景计划,每个计划都有一个起点 start 和一个终点 end,表示他想从景点 start 前往景点 end。由于小明希望节省体力,他想知道每个观景计划中从起点到终点的最短路径长度。 请你帮助小明计算出每个观景计划的最短路径长度。

【输入描述】

第一行包含两个整数 N, M, 分别表示景点的数量和道路的数量。

接下来的 M 行,每行包含三个整数 u, v, w,表示景点 u 和景点 v 之间有一条长度为 w 的双向道路。

接下里的一行包含一个整数 Q,表示观景计划的数量。

接下来的 Q 行,每行包含两个整数 start, end,表示一个观景计划的起点和终点。

【输出描述】

对于每个观景计划,输出一行表示从起点到终点的最短路径长度。如果两个景点之间不存在路径,则输出 -1。

【输入示例】

7 3 1 2 4 2 5 6 3 6 8 2 1 2 2 3

【输出示例】

4 -1

【提示信息】

从 1 到 2 的路径长度为 4,2 到 3 之间并没有道路。

1 <= N, M, Q <= 1000.

我很喜欢的一个博主Carl,在讲解动态规划时,将动态规划分为五步,即为动规五部曲:

  • 确定dp数组(dp table)以及下标的含义
  • 确定递推公式
  • dp数组如何初始化
  • 确定遍历顺序
  • 举例推导dp数组
1、引出为何用动态规划:

例如我们再求节点1 到 节点9 的最短距离,用二维数组来表示即:grid[1][9],如果最短距离是10 ,那就是 grid[1][9] = 10。

那 节点1 到 节点9 的最短距离 是不是可以由 节点1 到节点5的最短距离 + 节点5到节点9的最短距离组成呢?

即 grid[1][9] = grid[1][5] + grid[5][9]

节点1 到节点5的最短距离 是不是可以有 节点1 到 节点3的最短距离 + 节点3 到 节点5 的最短距离组成呢?

即 grid[1][5] = grid[1][3] + grid[3][5]

以此类推,节点1 到 节点3的最短距离 可以由更小的区间组成。到这个时候,已经递推公式已经开始明确喽。

在下方,我先给出算法,依照算法来讲解。

2、算法:
cpp 复制代码
#include <iostream>
#include <vector>
#include <list>
using namespace std;

int main() {
    int n, m, p1, p2, val;
    cin >> n >> m;

    vector<vector<vector<int>>> grid(n + 1, vector<vector<int>>(n + 1, vector<int>(n + 1, 10005)));  // 因为边的最大距离是10^4
    for(int i = 0; i < m; i++){
        cin >> p1 >> p2 >> val;
        grid[p1][p2][0] = val;
        grid[p2][p1][0] = val; // 注意这里是双向图

    }
    // 开始 floyd
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                grid[i][j][k] = min(grid[i][j][k-1], grid[i][k][k-1] + grid[k][j][k-1]);
            }
        }
    }
    // 输出结果
    int z, start, end;
    cin >> z;
    while (z--) {
        cin >> start >> end;
        if (grid[start][end][n] == 10005) cout << -1 << endl;
        else cout << grid[start][end][n] << endl;
    }
}

其核心就是

cpp 复制代码
    // 开始 floyd
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                grid[i][j][k] = min(grid[i][j][k-1], grid[i][k][k-1] + grid[k][j][k-1]);
            }
        }
    }
    // 别急,听我下发,细细讲解
3、确定dp数组(dp table)以及下标的含义:

Floyd-Warshall 算法中,dp 数组(或grid数组) 是用来存储从一个节点到另一个节点的最短路径的。为了理解代码中的grid[i][j][k],我们先分析下标的含义。

1、i:表示起始节点,从1到n。

2、j:表示目标节点,从1到n。

3、k:表示我们是否考虑节点 k 作为中间节点(即,当前路径是否通过节点 k)。k 从 1 到 n。

grid[i][j][k] 表示从节点 i 到节点 j,在考虑了前 k 个节点作为中间节点的情况下的最短路径。

因此,grid[i][j][k] 的值是从节点 i 到节点 j,经过前 k 个节点的最短路径的长度。

4、确定递推公式:

递推公式是 Floyd-Warshall 算法的核心。我们使用动态规划的思想逐步更新最短路径。

  • 状态转移公式

    grid[i][j][k] = min(grid[i][k][k - 1] + grid[k][j][k - 1], grid[i][j][k - 1])

    • grid[i][j][k - 1]:表示从节点 i 到节点 j,不经过节点 k 的最短路径。
    • grid[i][k][k - 1] + grid[k][j][k - 1]:表示从节点 i 到节点 j ,经过节点 k 的最短路径。

    这个递推公式的含义是:考虑是否通过节点 k 作为中间节点,如果通过节点 k 使得路径更短,则更新最短路径。

5、dp数组如何初始化:

在实际应用中,grid[i][j][0] 表示从节点 i 到节点 j 的最短路径(不经过任何节点)。

  • 初始化
    • 如果节点 i 和节点 j 之间有直接边(即图中存在一条从 ij 的边),则 grid[i][j][0] 初始化为这条边的权重。
    • 如果没有直接边,则初始化为无穷大(10005)。
    • grid[i][j][0]初始化为 0(因为一个节点到自己的路径是0)。

总而言之,Floyed算法 就是一种容易理解 ,可以算出任意两个节点之间的最短距离,代码编写简单的算法 。缺点就是时间复杂度比较高,不适合计算大量数据。

好了,到这里基本结束。看完题目,相信大家有所收获。再见。( ̄︶ ̄)↗

相关推荐
无限码力17 分钟前
小R的蛋糕分享
算法
終不似少年遊*26 分钟前
数据结构与算法之排序
数据结构·python·算法·排序算法
lgily-122538 分钟前
Python常用算法
开发语言·python·算法
闻缺陷则喜何志丹39 分钟前
【C++动态规划】1547. 切棍子的最小成本|2116
c++·算法·动态规划·力扣·最小·成本·棍子
James Shangguan1 小时前
LeetCode 704 如何正确书写一个二分查找
数据结构·算法·leetcode
Swift社区1 小时前
【Vue.js 组件化】高效组件管理与自动化实践指南
vue.js·算法·leetcode·职场和发展
快敲啊死鬼2 小时前
代码随想录18
算法
upgrador2 小时前
问卷信效度检验:Cronbach‘s α 与 KMO 值计算详解
算法·matlab
孑么2 小时前
力扣 二叉树的最大深度
java·算法·leetcode·职场和发展·深度优先·广度优先