Floyd算法:AcWing 854. Floyd求最短路

本文介绍了Floyd算法用于解决图中任意两点间最短路径的问题,特别是在稠密图中的应用。算法通过动态规划的方式,在O(n^3)的时间复杂度内完成计算。初始设置邻接矩阵,然后通过三层循环实现状态转移。错误的循环顺序会导致错误结果。提供的代码示例展示了Floyd算法的具体实现,并给出了AcWing854题目的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Floyd算法分析:

为了求出图中任意两点间的最短路径,当然可以把每个点作为起点,求解N次单源最短路径问题。

不过,在任意两点间最短路问题中,图一般比较稠密。使用 Floyd算法 可以在 O(N^3) 的时间内完成求解,并且程序实现非常简单。

d[k,i,j]表示“经过若干个编号不超过k的节点”从ij的最短路长度。

该问题可划分为两个子问题:经过编号不超过k-1的节点从ij,或者从i先到k再到j

于是:

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

初值为 d[0,i,j] = g[i,j],其中 g 为定义的邻接矩阵

可以看到, Floyd算法的本质是动态规划

k阶段,所以必须置于最外层循环中。ij附加状态,所以应该置于内层循环

以上也解释了为何很多初学者按照 i, j,k 的顺序执行循环,会得到错误的结果。

与背包问题的状态转移方程类似k 这一维可被省略。最初,我们可以直接用d保存邻接矩阵,然后执行动态规划的过程。

当最外层循环到 k 时,内层有状态转移:d[i,j]= min(d[i,j], d[i,k]+d[k,j])

最终 d[i,j] 就保存了 ij 的最短路长度。

代码片段:

//初始化:
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i==j) d[i][j]=0;
            else d[i][j]=inf;
            
// floyd算法结束后,d[a][b]表示a到b的最短距离
void floyd()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}

例题:AcWing 854. Floyd求最短路

在这里插入图片描述
在这里插入图片描述
时间复杂度:

O(n^3) , n 表示点数

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 210;
#define inf 0x3f3f3f3f
int d[N][N];
int n, m, k;

void floyd()
{
    for(int k=1; k<=n; ++k)
    {
        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j<=n; ++j)
            {
                d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
            }
        }
    }
}

int main()
{
    cin>>n>>m>>k;
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=n; ++j)
        if(i==j) d[i][j] = 0;
        else d[i][j] = inf;
    while(m--)
    {
        int x, y, z;
        cin>>x>>y>>z;
        d[x][y] = min(d[x][y], z);
    }
    floyd();
    while(k--)
    {
        int a, b;
        cin>>a>>b;
        cout<<(d[a][b]>inf/2 ? "impossible" : to_string(d[a][b]))<<endl;
    }
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值