佛洛伊德最短路径算法 讲解 以及 C++实现

佛洛伊德最短路径算法 讲解 以及 C++实现

  • 算法的特点:
    弗洛伊德算法(Floyd)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。

  • 算法的思路

通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入两个矩阵,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。矩阵P中的元素b[i][j],表示顶点i到顶点j经过了b[i][j]记录的值所表示的顶点。

假设图G中顶点个数为N,则需要对矩阵D和矩阵P进行N次更新。初始时,矩阵D中顶点a[i][j]的距离为顶点i到顶点j的权值;如果i和j不相邻,则a[i][j]=∞,矩阵P的值为顶点b[i][j]的j的值。 接下来开始,对矩阵D进行N次更新。第1次更新时,如果”a[i][j]的距离” > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示”i与j之间经过第1个顶点的距离”),则更新a[i][j]为”a[i][0]+a[0][j]”,更新b[i][j]=b[i][0]。 同理,第k次更新时,如果”a[i][j]的距离” > “a[i][k-1]+a[k-1][j]”,则更新a[i][j]为”a[i][k-1]+a[k-1][j]”,b[i][j]=b[i][k-1]。

涉及到了两个矩阵
  • 距离矩阵
    • 比较好理解,存储的是任意两点之间的最小距离
  • 路径矩阵
    • 路径矩阵的第i行j列代表的时顶点i与顶点j之间最短距离的中间节点。
    • 例如i,j两个点
      • 最短的边为i-j,则路径矩阵的path[i][j]=i
      • 最短的边为i-k-j,则path[i][j]=k,path[i][k]=i;
      • 最短的边为i-k-h-j,则path[i][j]=h,path[i][h]=k,path[i][k]=i;
    • 在实现对应的路径输出时进行寻路输出

3、Floyd算法的实例过程

这里写图片描述

第一步,我们先初始化两个矩阵,得到下图两个矩阵:
这里写图片描述

这里写图片描述

第二步,以v1为中阶,更新两个矩阵:
发现,a[1][0]+a[0][6] < a[1][6] 和a[6][0]+a[0][1] < a[6][1],所以我们只需要矩阵D和矩阵P,结果如下:

这里写图片描述

这里写图片描述

通过矩阵P,我发现v2–v7的最短路径是:v2–v1–v7

第三步:以v2作为中介,来更新我们的两个矩阵,使用同样的原理,扫描整个矩阵,得到如下图的结果:

这里写图片描述
这里写图片描述

  • 总结

FLoyd算法其实就是每次选择一个中介点,更新根据这个中节点可以连接起来的两个点的距离信息,在path中记录对应的路径

代码

代码设计了一个FloydWay类,实现了有向图和无向图的两种版本
写代码的时候偷了懒,路径的输出是倒着的

#include<bits/stdc++.h>
using namespace std;
const int INF=1e6;
//
class FloydWay{
    public:
    int vertex_num;
    void out_matrix(vector<vector<int>>&matrix)const{
        for(int i=0;i<matrix.size();i++){
            for(int u=0;u<matrix[i].size();u++){
                if(matrix[i][u]==INF||matrix[i][u]==-1){
                    cout<<left<<setw(5)<<"/";
                }else{
                    cout<<left<<setw(5)<<matrix[i][u];
                }
            }
            cout<<endl;
        }
    }
    void out_path_single(int i,int u){
        int k=u;
        cout<<k<<"<-";
        while(k!=i){
            k=path_matrix[i][k];
            cout<<k;
            if(k!=i){
                cout<<"<-";
                continue;
            }else{
                cout<<" | min dist: "<<min_dist_matirx[i][u];
                cout<<endl;
            }
        }
    }
    void out_all_path(){
        for(int i=0;i<vertex_num;i++){
            for(int u=i+1;u<vertex_num;u++){
                cout<<i<<"-"<<u<<": ";
                out_path_single(i,u);
            }
        }
    }
    vector<vector<int>>graph_matrix;//图矩阵
    vector<vector<int>>min_dist_matirx;//最短距离矩阵
    vector<vector<int>>path_matrix;//路径矩阵
    FloydWay(vector<vector<int>>graph_matri):graph_matrix(graph_matri),vertex_num(graph_matri.size()){
        //初始化最短距离矩阵,路径矩阵
        min_dist_matirx=vector<vector<int>>(vertex_num,vector<int>(vertex_num,INF));
        path_matrix=vector<vector<int>>(vertex_num,vector<int>(vertex_num,-1));
        for(int i=0;i<vertex_num;i++){
            for(int j=0;j<vertex_num;j++){
                min_dist_matirx[i][j]=graph_matrix[i][j];
                path_matrix[i][j]=i;
            }
        }
        cout<<"初始的距离矩阵"<<endl;
        out_matrix(min_dist_matirx);
        cout<<"初始的路径矩阵"<<endl;
        out_matrix(path_matrix);
    }
    void floyd_undirected(){//在无向图中的算法
    cout<<"###无向图###"<<endl;
        for(int i=0;i<vertex_num;i++){//第一层循环选择中间点
            for(int u=0;u<vertex_num;u++){//第二、三曾循环遍历顶点
                for(int k=0;k<vertex_num;k++){
                    if(min_dist_matirx[u][k]>min_dist_matirx[i][u]+min_dist_matirx[i][k]){
                        min_dist_matirx[u][k]=min_dist_matirx[i][u]+min_dist_matirx[i][k];
                        min_dist_matirx[k][u]=min_dist_matirx[i][u]+min_dist_matirx[i][k];
                        path_matrix[u][k]=i;
                        path_matrix[k][u]=i;
                        cout<<u<<"到"<<k<<"(双向)以"<<i<<"为中间节点可以取得更小值"<<endl;
                        cout<<"更新后的距离矩阵:"<<endl;
                        out_matrix(min_dist_matirx);
                        cout<<"更新后的路径矩阵:"<<endl;
                        out_matrix(path_matrix);
                    }
                }
            }
        }
        cout<<"最终的距离矩阵:"<<endl;
        out_matrix(min_dist_matirx);
        cout<<"最终的路径矩阵:"<<endl;
        out_matrix(path_matrix);
        out_all_path();
    }
    void floyd_directed(){//在有向图中的算法
        cout<<"###有向图###"<<endl;
        for(int i=0;i<vertex_num;i++){//第一层循环选择中间点
            for(int u=0;u<vertex_num;u++){//第二、三曾循环遍历顶点
                for(int k=0;k<vertex_num;k++){
                    if(min_dist_matirx[u][k]>min_dist_matirx[u][i]+min_dist_matirx[i][k]){
                        min_dist_matirx[u][k]=min_dist_matirx[u][i]+min_dist_matirx[i][k];
                        path_matrix[u][k]=i;
                        cout<<u<<"到"<<k<<"(单向)以"<<i<<"为中间节点可以取得更小值"<<endl;
                        cout<<"更新后的距离矩阵:"<<endl;
                        out_matrix(min_dist_matirx);
                        cout<<"更新后的路径矩阵:"<<endl;
                        out_matrix(path_matrix);
                    }
                }
            }
        }
        cout<<"最终的距离矩阵:"<<endl;
        out_matrix(min_dist_matirx);
        cout<<"最终的路径矩阵:"<<endl;
        out_matrix(path_matrix);
        out_all_path();
    }
};
int main(){
    vector<vector<int>>graph_undirected={
        {0, 1, 4, INF},
        {1, 0, INF, 1},
        {4, INF, 0, 1},
        {INF, 1, 1, 0}
    };
    vector<vector<int>>graph_directed={
        {0, 1, 4, INF},
        {INF, 0, INF, 1},
        {INF, INF, 0, INF},
        {INF, INF, 1, 0}
    };
    FloydWay(graph_undirected).floyd_undirected();
    FloydWay(graph_directed).floyd_directed();
}
运行结果

在这里插入图片描述

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是用C语言实现佛洛伊德算法求出任意两点间最短路径的示例代码: ```c #include <stdio.h> #include <stdlib.h> #define INF 99999 // 定义正无穷 int main() { int n, m; // n表示顶点数,m表示边数 scanf("%d %d", &n, &m); int dist[n][n]; // 定义距离矩阵 // 初始化距离矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) { dist[i][j] = 0; } else { dist[i][j] = INF; } } } // 读入边的信息,更新距离矩阵 for (int i = 0; i < m; i++) { int u, v, w; scanf("%d %d %d", &u, &v, &w); dist[u][v] = w; dist[v][u] = w; // 无向图需要更新两个方向 } // 佛洛伊德算法 for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; } } } } // 输出每对顶点间的最短路径和路径长度 for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { printf("从%d到%d的最短路径是:", i, j); int k = j; printf("%d", k); while (k != i) { for (int t = 0; t < n; t++) { if (dist[i][t] + dist[t][k] == dist[i][k]) { k = t; printf("<-%d", k); break; } } } printf("\n路径长度为:%d\n", dist[i][j]); } } return 0; } ``` 示例输入: ``` 6 10 0 1 1 0 2 12 1 2 9 1 3 3 2 4 5 3 2 4 3 4 13 3 5 15 4 5 4 5 0 7 ``` 示例输出: ``` 从0到1的最短路径是:1 路径长度为:1 从0到2的最短路径是:1<-2 路径长度为:10 从0到3的最短路径是:1<-3 路径长度为:4 从0到4的最短路径是:1<-3<-2<-4 路径长度为:14 从0到5的最短路径是:1<-3<-5 路径长度为:18 从1到2的最短路径是:2 路径长度为:9 从1到3的最短路径是:3 路径长度为:3 从1到4的最短路径是:3<-2<-4 路径长度为:14 从1到5的最短路径是:3<-5 路径长度为:18 从2到3的最短路径是:2<-3 路径长度为:12 从2到4的最短路径是:2<-4 路径长度为:14 从2到5的最短路径是:2<-3<-5 路径长度为:21 从3到4的最短路径是:4 路径长度为:13 从3到5的最短路径是:5 路径长度为:15 从4到5的最短路径是:5 路径长度为:4 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值