Floyd算法(求解多源最短路径)(动态规划思想)(邻接矩阵)(C++实现)

Floyd算法(求解多源最短路径)(动态规划思想)(邻接矩阵)(C++实现)

实现代码

#include<bits/stdc++.h>
using namespace std;

const int INF = 0xFFFF;

struct Node{
    int num;
    int dist;
    bool operator < (const Node& rhs) const{
        return dist > rhs.dist;
    }
};

class AdjacentMatrix
{
    public:
        AdjacentMatrix(int vexNum, vector< pair< pair<int,int>, int> > net);
        void floyd();
    private:
        void createDirectedNet(vector< pair< pair<int, int>, int> > net);
        int vexNum;
        vector< vector<int> > floydMatrix;
        vector< vector<int> > floydPath;
};

AdjacentMatrix::AdjacentMatrix(int vexNum,vector< pair< pair<int,int>, int> > net){
    this->vexNum = vexNum;
    floydMatrix.resize(vexNum);
    floydPath.resize(vexNum);
    for(int i = 0; i < vexNum; i++){
        floydMatrix[i].resize(vexNum);
        floydPath[i].resize(vexNum);
        for(int j = 0; j < vexNum; j++) {
            floydMatrix[i][j] = INF;
        }
    }
    createDirectedNet(net);
}

void AdjacentMatrix::createDirectedNet(vector< pair< pair<int, int>, int> > net) {
	//建立有向网
    for (int i = 0; i < vexNum; i++) {
        for (int j = 0; j < vexNum; j++) {
        	//初始距离设为无穷大
            floydMatrix[i][j] = (i == j ? 0 : INF);
        }
    }
    for (int i = 0; i < net.size(); i++) {
    	//自身距离设为0
        floydMatrix[net[i].first.first - 1][net[i].first.second - 1] = net[i].second;
    }
}

void AdjacentMatrix::floyd() {
    for (int k = 0; k < vexNum; k++) {
    	//考虑所有顶点为路径绕行的顶点,并更新floydMatrix和floydPath
        for (int i = 0; i < vexNum; i++) {
            for (int j = 0; j < vexNum; j++) {
                if (floydMatrix[i][j] > floydMatrix[i][k] + floydMatrix[k][j]) {
                	//状态转移方程,若存在一个点顶点能够使得,顶点i到顶点j经过它的路径比未经过它的路径更短
                	//更新对应最短路径累积边权
                	//类似Dijkstra算法
                    floydMatrix[i][j] = floydMatrix[i][k] + floydMatrix[k][j];
                    floydPath[i][j] = k + 1;//更新路径
                }
            }
        }
    }
    //输出结果~~
    printf("\nFloyd Shortest Edge Weight Matrix:\n");
    for (int i = 0; i < vexNum; i++) {
        for (int j = 0; j < vexNum; j++) {
            printf("%d ", floydMatrix[i][j]);
        }
        printf("\n");
    }
    printf("\nFloyd Shortest Path:\n");
    for (int i = 0; i < vexNum; i++) {
        for (int j = 0; j < vexNum; j++) {
            printf("%d ", floydPath[i][j]);
        }
        printf("\n");
    }
    //~~
}


int main(int argc, char const *argv[])
{
    vector< pair< pair<int,int>, int> > net;
    int node1, node2;
    int weight;
    int vexNum;
    if(argc == 1){
        argv[1] = "1.txt";
    }
    freopen(argv[1],"r", stdin);
    scanf("%d", &vexNum);
    while(~scanf("%d%d%d", &node1, &node2, &weight))
        net.push_back(make_pair(make_pair(node1, node2), weight));
    AdjacentMatrix AM(vexNum, net);
    AM.floyd();
    return 0;
}

算法思路

  • Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。——百度百科
  • 算法基本思想:递推产生一个n阶方针序列floydMatrix(-1), floydMatrix(0), …, floydMatrix(k), …, floydMatrix(n -1),其中floydMatrix(k)[i][j]表示从顶点vi到顶点vj之间的路径长度,k表示绕行(路径经过顶点k)第k个顶点的运算步骤,floydMatrix(k)[i][j]是从顶点vi到顶点vj的路径中间顶点不大于k的最短路径累积边权值(每次迭代就会多考虑一个可以绕行的k顶点)
  • 状态转移方程:floydMatrix(k)[i][j] = min{floydMatrix(k)[i][j], floydMatrix(k - 1)[i][k] + floydMatrix(k - 1)[k][j]}
  • Floyd算法是一个迭代的过程,每一次迭代从顶点vi到vj的最短路径上就多考虑一个顶点,经过n此迭代后,得到的 floydMatrix(n -1)就是顶点vi到vj的最短路径边累积权值,保存了任意一对顶点的最短路径累积边权,而floydPath则保存用于回溯最短路径的顶点编号
  • 算法时间复杂度O(|V| ^ 3)

测试数据

3
1 2 6
1 3 13
2 1 10
2 3 4
3 1 5

测试结果

Floyd Shortest Edge Weight Matrix:
0 6 10
9 0 4
5 11 0

Floyd Shortest Path:
0 0 2
3 0 0
0 1 0

样例

  • 样例图解
  • Floyd算法执行过程
  • 本样例参考王道考研数据结构

鸣谢

感谢王道论坛及其产品提供的宝贵建议
感谢百度百科提供的百科知识

最后

  • 回溯floydPath可以得到任意一对顶点的最短路径
  • Floyd算法允许存在负权值的边,但不允许包含负权值的边构成的回路
  • 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!
发布了39 篇原创文章 · 获赞 25 · 访问量 3383

猜你喜欢

转载自blog.csdn.net/qq_44486439/article/details/105577171