「图论」最短路径长度-Floyd

【1】为什么需要弗洛伊德算法?

带权图中单个源点到所有顶点的最短路径问题可以用《迪杰斯特拉算法》求解。

那如果要求图中每一个顶点与其它顶点之间的最短路径呢?类似可以想到的方法为:

每次以一个顶点为源点,重复执行地杰斯特拉算法算法n次。

这样,理论上我们便可以求得每一个顶点与其它顶点的最短路径,总的执行时间为O(n3)。

好吧!为了实现这个中需求,可以采用另外一种求解算法:弗洛伊德算法。

为了更好的理解弗洛伊德算法的精妙,我们先看简单的案例。

如下图是一个最简单的3个顶点连通网图:

【2】弗洛伊德算法

弗洛伊德算法是非常漂亮的算法,简洁直观大气上档次。

不过很可惜由于它的三重循环,因此也是O(n*n*n)的时间复杂度。

如果你面临需要求所有顶点至所有顶点的最短路径问题?

它是很好的选择。算法代码如下图:

关于本算法再不做详细赘述。如若感兴趣,下面的代码案例可以自己琢磨琢磨。

【3】弗洛伊德算法实现

注意:本算法的实现案例与迪杰斯特拉算法相同都是在求同一个图的最短路径问题。

不同的是这个算法可以求得所有顶点到所有顶点的最短路径。

模拟实现代码如下:


#include <iostream>
#include "SeqList.h"
#include <iomanip>
using namespace std;

#define  INFINITY  65535

typedef    int* pInt;
typedef pInt* ppInt;

template<class NameType, class DistType>
class Graph
{
private:
    SeqList<NameType> Vertices;
    DistType **Edges;
    int nVer, nEdges;

public:
    Graph() 
        : Edges(NULL)
        , nEdges(0)
        , nVer(0)
    {}
    ~Graph()
    {}

public:
    int GetVer() const
    {
        return nVer;
    }

    istream & operator>>(istream &in)
    {
        int v, u, value;
        int i, j;
        NameType item;
        cout << "请输入顶点的个数: " << endl;
        in >> nVer;
        cout << "请输入顶点的数据信息: " << endl;
        for (i = 0; i < nVer; ++i)
        {
            in >> item;
            Vertices.push_back(item);    // 保存全部顶点
        }
        /二维数组的创建并初始化
        Edges = new DistType*[nVer]; // DistType *ar[10];
        for (i = 0; i < nVer; ++i)
        {
            Edges[i] = new DistType[nVer];
            for (j = 0; j < nVer; ++j)
            {
                Edges[i][j] = 0;
            }
        }
        cout << "请输入边的个数: " << endl;
        in >> nEdges;
        cout << "请输入边的信息:" << endl;
        for (i = 0; i < nEdges; ++i)
        {
            in >> v >> u >> value;
            Edges[v][u] = value;
            Edges[u][v] = value;
        }
        return in;
    }
    ostream & operator<<(ostream &out) const
    {
        int i, j;
        out << "顶点信息 " << endl;
        for (i = 1; i <= nVer; ++i)
        {
            out << Vertices[i] << setw(5);
        }
        out << endl;
        out << "矩阵信息:" << endl;
        out << setw(10);
        for (i = 1; i <= nVer; ++i)
        {
            out << Vertices[i] << setw(5);
        }
        out << endl;
        for (i = 0; i < nVer; ++i)
        {
            out << Vertices[i+1] << setw(5);
            for (j = 0; j < nVer; ++j)
            {
                if (0 == Edges[i][j] && i != j)
                    Edges[i][j] = INFINITY;
                cout << Edges[i][j] << setw(5);
            }
            out << endl;
        }
        out << endl;

        return out;
    }
    // 弗洛伊德算法实现
    void ShortestPath_Floyd(int** p, int** D)
    {
        int v = 0, w = 0, k = 0;
        // 初始化数据
        for (v = 0; v < nVer; ++v)
        {
            for (w = 0; w < nVer; ++w)
            {
                D[v][w] = Edges[v][w];
                p[v][w] = w;
            }
        }
        for (k = 0; k < nVer; ++k)
        {
            for (v = 0; v < nVer; ++v)
            {
                for(w = 0; w < nVer; ++w)
                {
                    if (D[v][w] > D[v][k] + D[k][w])
                    {
                        D[v][w] = D[v][k] + D[k][w];
                        p[v][w] = p[v][k];
                    }
                }
            }
        }
    }
    // 打印矩阵信息
    void PrintArray(ppInt pp)
    {
        cout << setw(10);
        for (int i = 1; i <= nVer; ++i)
        {
            cout << Vertices[i] << setw(5);
        }
        cout << endl;
        for (int i = 0; i < nVer; ++i)
        {
            cout << Vertices[i+1] << setw(5);
            for (int j = 0; j < nVer; ++j)
            {
                cout << pp[i][j] << setw(5);
            }
            cout << endl;
        }
        cout << endl;
    }
    // 求解完成后打印所以路径信息
    void PrintPath(ppInt pp, ppInt DD)
    {
        int v, k, w;
        for (v = 0; v < nVer; ++v)
        {
            for (w = v+1; w < nVer; ++w)
            {
                cout << "V" << v << "-->" << "V" << w << " weight:" << DD[v][w] << endl;
                k = pp[v][w];
                cout << "Path:V" << v;
                while (k != w)
                {
                    cout << "-->V" << k;
                    k = pp[k][w];
                }
                cout << "-->V" << w << endl;
            }
        }
        cout << endl;
    }
};

template<class NameType, class DistType>
istream & operator>>(istream &in, Graph<NameType,DistType> &g)
{
    g >> in;
    return in;
}

template<class NameType, class DistType>
ostream & operator<<(ostream &out, const Graph<NameType,DistType> &g)
{
    g << out;
    return out;
}


void main()
{
    Graph<char, int> myg;
    cin >> myg;
    cout << "打印所有输入信息:" << endl;
    cout << myg << endl;
    cout << "求最短路径....." << endl;
    int numVer = myg.GetVer();
    ppInt pPathmatirx = new pInt[numVer];
    for (int i = 0; i < numVer; ++i)
    {
        pPathmatirx[i] = new int[numVer];
        for (int j = 0; j < numVer; ++j)
        {
            pPathmatirx[i][j] = 0;
        }
    }
    ppInt pShortPath = new pInt[numVer];
    for (int i = 0; i < numVer; ++i)
    {
        pShortPath[i] = new int[numVer];
        for (int j = 0; j < numVer; ++j)
        {
            pShortPath[i][j] = 0;
        }
    }
    myg.ShortestPath_Floyd(pPathmatirx, pShortPath);
    cout << "分别打印矩阵结果:" << endl;
    cout << "各顶点最短路径:" << endl;
    myg.PrintArray(pShortPath);
    cout << "各最短路径前驱顶点下标值:" << endl;
    myg.PrintArray(pPathmatirx);
    cout << "打印全部最短路径:"<< endl;
    myg.PrintPath(pPathmatirx, pShortPath);
    // 释放二维数组
    for (int i = 0; i < numVer; ++i)      
        delete []pPathmatirx[i];   
    delete []pPathmatirx;
    for (int i = 0; i < numVer; ++i)      
        delete []pShortPath[i];   
    delete []pShortPath;
    pPathmatirx = NULL;
    pShortPath = NULL;
}
// 备注:
// 最短路径弗洛伊德算法实现
// 整理于2013-12-05
// 测试输入程序为:
/*
请输入顶点的个数:
9
请输入顶点的数据信息:
A B C D E F G H I
请输入边的个数:
16
请输入边的信息:
0 1 1
0 2 5
1 2 3
1 3 7
1 4 5
2 4 1
2 5 7
3 4 2
3 6 3
4 5 3
4 6 6
4 7 9
5 7 5
6 7 2
6 8 7
7 8 4
打印所有输入信息:
顶点信息
A    B    C    D    E    F    G    H    I
矩阵信息:
A    B    C    D    E    F    G    H    I
A    0    1    5655356553565535655356553565535
B    1    0    3    7    565535655356553565535
C    5    3    065535    1    7655356553565535
D65535    765535    0    265535    36553565535
E65535    5    1    2    0    3    6    965535
F6553565535    765535    3    065535    565535
G655356553565535    3    665535    0    2    7
H65535655356553565535    9    5    2    0    4
I655356553565535655356553565535    7    4    0


求最短路径.....
分别打印矩阵结果:
各顶点最短路径:
A    B    C    D    E    F    G    H    I
A    0    1    4    7    5    8   10   12   16
B    1    0    3    6    4    7    9   11   15
C    4    3    0    3    1    4    6    8   12
D    7    6    3    0    2    5    3    5    9
E    5    4    1    2    0    3    5    7   11
F    8    7    4    5    3    0    7    5    9
G   10    9    6    3    5    7    0    2    6
H   12   11    8    5    7    5    2    0    4
I   16   15   12    9   11    9    6    4    0

各最短路径前驱顶点下标值:
A    B    C    D    E    F    G    H    I
A    0    1    1    1    1    1    1    1    1
B    0    1    2    2    2    2    2    2    2
C    1    1    2    4    4    4    4    4    4
D    4    4    4    3    4    4    6    6    6
E    2    2    2    3    4    5    3    3    3
F    4    4    4    4    4    5    7    7    7
G    3    3    3    3    3    7    6    7    7
H    6    6    6    6    6    5    6    7    8
I    7    7    7    7    7    7    7    7    8

打印全部最短路径:
V0-->V1 weight:1
Path:V0-->V1
V0-->V2 weight:4
Path:V0-->V1-->V2
V0-->V3 weight:7
Path:V0-->V1-->V2-->V4-->V3
V0-->V4 weight:5
Path:V0-->V1-->V2-->V4
V0-->V5 weight:8
Path:V0-->V1-->V2-->V4-->V5
V0-->V6 weight:10
Path:V0-->V1-->V2-->V4-->V3-->V6
V0-->V7 weight:12
Path:V0-->V1-->V2-->V4-->V3-->V6-->V7
V0-->V8 weight:16
Path:V0-->V1-->V2-->V4-->V3-->V6-->V7-->V8
V1-->V2 weight:3
Path:V1-->V2
V1-->V3 weight:6
Path:V1-->V2-->V4-->V3
V1-->V4 weight:4
Path:V1-->V2-->V4
V1-->V5 weight:7
Path:V1-->V2-->V4-->V5
V1-->V6 weight:9
Path:V1-->V2-->V4-->V3-->V6
V1-->V7 weight:11
Path:V1-->V2-->V4-->V3-->V6-->V7
V1-->V8 weight:15
Path:V1-->V2-->V4-->V3-->V6-->V7-->V8
V2-->V3 weight:3
Path:V2-->V4-->V3
V2-->V4 weight:1
Path:V2-->V4
V2-->V5 weight:4
Path:V2-->V4-->V5
V2-->V6 weight:6
Path:V2-->V4-->V3-->V6
V2-->V7 weight:8
Path:V2-->V4-->V3-->V6-->V7
V2-->V8 weight:12
Path:V2-->V4-->V3-->V6-->V7-->V8
V3-->V4 weight:2
Path:V3-->V4
V3-->V5 weight:5
Path:V3-->V4-->V5
V3-->V6 weight:3
Path:V3-->V6
V3-->V7 weight:5
Path:V3-->V6-->V7
V3-->V8 weight:9
Path:V3-->V6-->V7-->V8
V4-->V5 weight:3
Path:V4-->V5
V4-->V6 weight:5
Path:V4-->V3-->V6
V4-->V7 weight:7
Path:V4-->V3-->V6-->V7
V4-->V8 weight:11
Path:V4-->V3-->V6-->V7-->V8
V5-->V6 weight:7
Path:V5-->V7-->V6
V5-->V7 weight:5
Path:V5-->V7
V5-->V8 weight:9
Path:V5-->V7-->V8
V6-->V7 weight:2
Path:V6-->V7
V6-->V8 weight:6
Path:V6-->V7-->V8
V7-->V8 weight:4
Path:V7-->V8
 */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值