所有顶点之间的最短路径——Floyd算法

问题的提出:已知一个有向网(或无向网),对每一对顶点(vi!=vj),要求求出vi和vj之间的最短路径和最短路径长度。

解决方法:(1)轮流以每个顶点为源点,重复执行Dijkstra算法或Bellman—Ford算法n次,就可以求出每一对顶点之间的最短路径和最短路径长度。总的时间复杂度为O(n^3)或O(n^2+ne);

(2)采用Floyd算法。时间复杂度与上述相同,但Floyd算法更直接。

算法思想:对一个顶点个数为n的有向网(或无向网),设置一个n*n的方阵A^(k),其中除对角线的矩阵元素都为0外,其他元素A^(k)[i][j] (i!=j)表示从顶点vi到顶点vj的最短路径长度,k表示运算步骤


初始时:以任意两个顶点之间的直接有向边权值作为最短路劲长度。对于任意两个顶点,若他们之间存在有向边,则以此边的权值作为它们之间的最短路径长度,若他们之间不存在有向边,则以无穷大作为他们之间的最短路径长度。

以后逐步尝试在原路径中加入其他顶点作为中间顶点,如果加入中间顶点后,得到的路径长度比原来的最短路径长度减少了则以此新路径代替原路径,修改矩阵元素,更新为更短的路径长度

A^(k)[i][j]表示从顶点vi到顶点vj的,中间顶点序号不大于k的最短路径长度。采用递推的方式计算A^(k)[i][j].  A^(n-1)[i][j]是最终求得的最短路径长度。


例题:求所有顶点之间的最短路径长度及其最短路径。


测试数据:
输入:

4
0 1 1
0 3 4
1 2 9
1 3 2
2 0 3
2 1 5
2 3 8
3 2 6
-1 -1 -1

输出:

0=>1    1       0-1
0=>2    9       0-1-3-2
0=>3    3       0-1-3
1=>0    11     1-3-2-0
1=>2    8       1-3-2
1=>3    2       1-3
2=>0    3       2-0
2=>1    4       2-0-1
2=>3    6       2-0-1-3
3=>0    9       3-2-0
3=>1    10     3-2-0-1
3=>2    6       3-2

测试数据输出结果

#include<cstdio>
#include<iostream>
#include<cstring>
#define INF 0x3f3f3f3f
#define MAXN 8
using namespace std;
int map[MAXN][MAXN];
int A[MAXN][MAXN];
int path[MAXN][MAXN];
int n;
void Floyd()
{
    int i,j,k;
    for(i=0;i<n;i++)///对A[][]和path[][]进行初始化
    {
        for(j=0;j<n;j++)
        {
            A[i][j]=map[i][j];
            if(i!=j&&A[i][j]<INF)
                path[i][j]=i;
            else
                path[i][j]=-1;
        }
    } 
    
    for(k=0;k<n;k++)///加入v0时,判断能通过V0连接起来的点是否
    {               ///  需要更新权值
        for(i=0;i<n;i++)///加入V1时,判断能通过v1或v1,v0的点是否需要更新权值
        {              ///加入V2时,判断能通过V2或V1,V2或V0,V1,V2的点是否需要
            for(j=0;j<n;j++)///更新权值
            {                ///依次类推,直到判断完所有的点
                if(k==i||k==j)
                    continue;
                if(A[i][k]+A[k][j]<A[i][j])
                {
                    A[i][j]=A[i][k]+A[k][j];
                    path[i][j]=path[k][j];
                }
            }
        }
    }
}
int main()
{
    int i,j;
    int u,v,w;
    scanf("%d",&n);
    while(1)
    {
        scanf("%d%d%d",&u,&v,&w);
        if(u==-1&&v==-1&&w==-1)
            break;
        map[u][v]=w;
    }
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                if(i==j)
                    map[i][j]=0;
                else if(map[i][j]==0)
                     map[i][j]=INF;
            }
        }
        Floyd();
        int shortest[MAXN];
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                if(i==j) continue;
                printf("%d=>%d\t%d\t",i,j,A[i][j]);
                memset(shortest,0,sizeof(shortest));
                int k=0;
                shortest[k]=j;  ///第一个下标存储终点
                while(path[i][shortest[k]]!=i)///不等于起点
                {
                    k++;
                    shortest[k]=path[i][shortest[k-1]];
                }
                k++;
                shortest[k]=i;
                for(int t=k;t>0;t--)
                    printf("%d-",shortest[t]);
                printf("%d\n",shortest[0]);
             }
        }
     return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值