弗洛伊德(Floyd)算法(多源最短路径)

弗洛伊德算法比较适合稠密图,形式上比较优雅,核心代码只有五行。

for (k = 1; k <= g.v; k++)
        for (i = 1; i <= g.v; i++)
            for(j = 1; j <= g.v; j++)
                if (g.matrix[i][j] > g.matrix[i][k] + g.matrix[k][j])
                    g.matrix[i][j] = g.matrix[i][k] + g.matrix[k][j];
             

这段代码的基本思想就是:最开始只允许1号顶点进行中转,接下来只允许1号和2号顶点进行中转......允许经过1~n号的所有顶点进行中转,求任意两点间的最短路程。用一句概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。

完整代码如下:

/************************************************************************
*
* 文件名:7.1.2.cpp
*
* 文件描述:弗洛伊德算法(多源最短路径)适合稠密图
*
* 创建人:  fdk

* 时  间:  2018-09-05
*
* 版本号:1.0
*
* 修改记录:
*
************************************************************************/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#include<limits.h>
#define N 100
#define M 100
using namespace std;

/*定义矩阵结构*/
typedef struct node
{
    int matrix[N][M];    //定义邻接矩阵
    int v;               //结点数
    int e;               //边数
}MGraph;

/*弗洛伊德算法*/
void Floyd(MGraph g, int path[10][10])
{
    int i, j, k;
    cout << "-----更新前路径------" << endl;
    for (i = 1; i <= g.v; i++)
    {
        for (j = 1; j <= g.v; j++)
        {
            /*如果顶点i和顶点j之间不存在通路则输出无穷,否则输出最小值*/
            if (g.matrix[i][j] == 9999)
                cout << "∞" << " ";
            else
                cout << g.matrix[i][j] << " ";
        }
        cout << endl;
    }

    cout << "-----更新后path路径------" << endl;
    for (i = 1; i <= g.v; i++)
    {
        for (j = 1; j <= g.v; j++)
        {
            cout << path[i][j] << " ";
        }
        cout << endl;
    }

    /*弗洛伊德核心代码5行*/

    //从i号顶点到j号顶点,只经过前k号顶点的最短路程
    for (k = 1; k <= g.v; k++)
        for (i = 1; i <= g.v; i++)
            for(j = 1; j <= g.v; j++)
                if (g.matrix[i][j] > g.matrix[i][k] + g.matrix[k][j])
                {
                    /*如果存在顶点k使得i到j的距离变短,则更新距离*/
                    g.matrix[i][j] = g.matrix[i][k] + g.matrix[k][j];
                    path[i][j] = path[i][k];  //更新路径,为了顺序输出
                }
    cout << "-----更新后路径------" << endl;
    for (i = 1; i <= g.v; i++)
    {
        for (j = 1; j <= g.v; j++)
        {
            if (g.matrix[i][j] == 9999)
                cout << "∞" << " ";
            else
                cout << g.matrix[i][j] << " ";
        }
        cout << endl;
    }

    /*打印更新后的path*/
    cout << "-----更新后path路径------" << endl;
    for (i = 1; i <= g.v; i++)
    {
        for (j = 1; j <= g.v; j++)
        {
            cout << path[i][j] << " ";
        }
        cout << endl;
    }
    /*打印路径*/
    for (i = 1; i <= g.v; i++)
    {
        for (j = 1; j <= g.v; j++)
        {
            if (g.matrix[i][j] == 9999)
            {
                cout << "从点" << i << "到点" << j << "不存在通路" << endl;
            }
            else
            {
                cout << "从点" << i << "到点" << j << "的最短路径为" << g.matrix[i][j];
                cout << " 经过的点为: " << i << " ";

                /*顺序输出路径上的顶点*/
                k = path[i][j];
                while (k != j)
                {
                    cout << k << " ";
                    k = path[k][j];
                }
                cout << j;
            }
            cout << endl;
        }
    }
}


int main()
{
    int v, e;  //v为顶点e为边
    cin >> v >> e;

    int i, j;

    int s, t, w;  //从顶点s到顶点t权值为w

    int path[10][10];
    MGraph g;
    g.e = e;
    g.v = v;
    /*初始化*/
    for (i = 1; i <= v; i++)
    {
        for (j = 1; j <= v; j++)
        {
            if (i == j)
                g.matrix[i][j] = 0;
            else
                g.matrix[i][j] = 9999;
            path[i][j] = j;
        }
    }

    /*输入带权的路径*/
    for (i = 1; i <= e; i++)
    {
        cin >> s >> t >> w;
        g.matrix[s][t] = w;
    }

    Floyd(g, path);
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值