最短路径——Floyd算法

1. 背景:

Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。

2. 算法介绍:

完全最短路径问题要求找出一个有n个节点的加权连通图中每个节点到其他所有节点之间的最短距离。
最短路径——Floyd算法_第1张图片
可以使用类似于Washall算法的方法来生成这个最短距离矩阵,这就是Floyd算法。 Floyd算法通过一系列n阶矩阵来计算一个n节点加权图的最短距离矩阵。
在这里插入图片描述
以下图为例,一起来看一下Floyd算法每步的拓展情况:
最短路径——Floyd算法_第2张图片
根据该有向图可以得到任意两点间的距离矩阵(邻接矩阵),即没有跳板,能直接到达则记录距离,不能直接到达则记为∞,自己到自己的距离为0。如下图所示:
最短路径——Floyd算法_第3张图片
然后一个一个节点考虑,先以a为跳板,重新遍历每两点距离,观察哪些距离可以更新(因为这是有向图,因此不是对称矩阵),如:初始矩阵 b->c 不存在通路,即为 ∞ ,当引入节点a后,以a作为跳板可使,b到c的距离更新为b->a->c ,即为5。同理,我们每次增加一个跳板,不断更新矩阵中的距离:
最短路径——Floyd算法_第4张图片
最短路径——Floyd算法_第5张图片
最终得到任意一个节点到其他节点的最短路径矩阵。

3. 复杂度分析:

一共n个节点,Floyd算法每次都要维护n*n的矩阵,一共循环n次,因此时间复杂度为O(n3).

4. 对比Dijkstra:

其实了解过Dijkstra的话可以发现Dijkstra和Floyd算法相似度还是蛮大的,当然也存在很大区别。
(1)Dijkstra和Floyd都可以找到从一点到另一点的最短路径,只不过区别就是Dijkstra是解决单源最短路径(复杂度为O(n2)),而Floyd能解决任意源最短路径问题。但是只需要遍历N遍Dijkstra,就能找到任意源的最短路径,但是此时的复杂度也就变成O(n3),和Floyd相同。
(2)Dijkstra和Floyd看似思路相同,都是每次增加一个跳板,然后更新两节点间距离。但是两者的方法存在本质区别:Dijkstra是贪心算法自顶向下求解,通过选择将问题归约为小的子问题。而Floyd是动态规划思想,是自底向下。

5. 代码:

#include 
#include 
using namespace std;

vector<vector<int> > a; // a表示邻接矩阵
vector<vector<int> > d; //保存每对结点之间最短路径
int n;  //节点数
// 创建邻接矩阵
void  CreateA (){
    scanf("%d", &n);
    for(int i = 0; i < n; ++i){
        vector<int> v;
        int v1;
        for(int j = 0; j < n; ++j){
            scanf("%d", &v1);
            v.push_back(v1);
        }
        a.push_back(v);
    }
}
void Dis (){
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
            d[i][j] = a[i][j];
        }
    }
    // 遍历每个节点k,看将该节点作为跳板后是否可以更新节点(距离变短则更新)
    for(int k = 0; k < n; ++k){
        for(int i = 0; i < n; ++i){
            for(int j = 0; j < n; ++j){
                if(d[i][k] + d[k][j] < d[i][j])
                    d[i][j] = d[i][k] + d[k][j];
            }
        }
    }
}
int main()
{
    CreateA();
    Dis();
    return 0;
}

6. 附录:

代码中涉及了二维vector的操作,若对二维vector操作不熟悉,可参考blog:
https://blog.csdn.net/m0_51339444/article/details/123876749

你可能感兴趣的:(C++,算法,算法,贪心算法)