acm_floyd任意两点的最短路(最简单无脑的最短路算法)

算法作用

求给定图中任意两点间的最短距离

时间复杂度

O(v^3) V是顶点个数

代码实现(3个for)

g是用邻接矩阵传入的图, 如果两点之间没有路径, 设成inf, 否则设成边权, n是顶点个数, 顶点编号默认0~n-1, 最后i, j点的最短路径在g[i][j]中

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

算法拓展

可用用floyd判环g[i][j]表示i, j之间有路, 如果g[i][j] = 1 并且g[j][i]=1 那么i, j之间有环, 同时取最小值应该改成二进制的或运算

算法证明

根本思想方法来自动态规划;
假设现在已经有了从i到j的最短路, 那么有两种情况:
为方便证明给出图例
这里写图片描述
图1. floyd简单证明图

可以知道i到j的最短路是i->k1->k2->k3->j
那么直接给出转移方程g[i][j] = min(g[i][j], g[i][k] + g[k][j]) 代表的意思是g[i][j]之间的最短路等于
1. 本来i到j的距离
2. i 经过一个中间点k再到j
这些路中取最小
意思也很好理解: i到j的最短距离要么是i到j的本来就有的距离(上图的100的边权) 要么先从i到k求到最短距离, 然后再从k到j找到最短距离, 两者加起来即可

代码实现的具体过程及思路

一个一个的加点, 直到加完所有点
比如本来有了图g
1. 加入0号点, 那么图g中和0有关的可以互相到达的两点的最短路径就找出来了
2. 加入1号点, …..
3. 加入2号点, …..
……

为什么能实现呢?
比如在第三步中的加入2号点,
1. 任意两个点的最短路径如果和2号点有关, 那么最短路径一定是g[i][2] + g[2][j], 而在前面的步骤中我已经求出了g[i][2] 和g[2][i], 所以在取min的过程中更新了g[i][j]
2. 如果和2号点无关, 那么g[i][j]一定在是前面求出的最小步骤
举个例子:
加入求1 到 4 的最短路径: 假设是1 –> 3 –> 0 –> 4
1. 加入0点, 那么我就求出了3到4的最短路径也就是3 –> 0 –> 4这条路
2. 加入1点, 由于是这条路的起点, 所以其实他是不变的, 也可以理解成它求出了1–>这条路
3. 加入2点, 由于这条最短路不包含2点, 所以对这条路没有影响
4. 加入3点, 求出1到4的最短路径, 因为在前面已经求出了1–>3的最短路径和3 –> 4的最短路径, 所以这里的min操作就可以取到1 –> 3 –> 0 –> 4这条路径了
……
如此下去, 只要取完所有的n个点, 就求出了解了, 动态规划思想好的应该更容易理解这些……

复杂度证明

明显的3重循环 所以复杂度是O(v^3) v是顶点个数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值