判断有向图g中顶点i到顶点j是否有路径_7.4.3 最短路径问题(2)Floyd算法

079b9eb58563cabd7cf9da490b84f65d.png

返回目录:

Chilan Yu:《数据结构》目录链接​zhuanlan.zhihu.com
16500f0d365c95a84f59b2d2bd13ca8c.png

迪杰斯特拉算法只能求出从源点到其他顶点的最短路径,欲求任意一对顶点间的最短路径,可以将每一顶点作为源点,重复调用迪杰斯特拉算法n次,其时间复杂度为

下面介绍一种形式更简单的方法,即佛罗伊德算法,其时间复杂度也是


2. 求任意一对顶点间的最短路径

例7.5:利用佛罗伊德算法,求图7.27(a)所示的带权有向图中G6的每一对顶点之间的最短路径P及其长度D。7.27(c)给出了G6的每一对顶点之间的最短路径P及其路径长度D。

a7037d10fd5079121d7c31cafceca734.png

算法思想

设图g用邻接矩阵法表示,求图g中任意一对顶点vi、vj间的的最短路径。(注:以下序号是与图7.27中D、P的上标序号对应的)。

(-1)将vi到vj 的最短的路径长度初始化为

,然后进行如下n次比较和修正:

(0)在vi、vj间加入顶点v0,比较(vi,v0,vj)和(vi,vj)的路径的长度,取其中较短的路径作为vi到vj 的且中间顶点号不大于0的最短路径。

(1)在vi、vj间加入顶点v1,得(vi,…, v1)和(v1,…, vj),其中(vi,…,v1)是vi到v1 的且中间顶点号不大于0的最短路径,(v1,…,vj) 是v1到vj 的且中间顶点号不大于0的最……短路径,这两条路径在上一步中已求出。将(vi,…,v1,…,vj)与上一步已求出的且vi到vj 中间顶点号不大于0的最短路径比较,取其中较短的路径作为vi到vj 的且中间顶点号不大于1的最短路径。

(2)在vi、vj间加入顶点v2,得(vi,…,v2)和(v2,…,vj),其中(vi,…,v2)是vi到v2 的且中间顶点号不大于1的最短路径,(v2,…,vj) 是v2到vj 的且中间顶点号不大于1的最短路径,这两条路径在上一步中已求出。将(vi,…,v2,…,vj)与上一步已求出的且vi到vj 中间顶点号不大于1的最短路径比较,取其中较短的路径作为vi到vj 的且中间顶点号不大于2的最短路径。

………

依次类推,经过n次比较和修正,在第(n-1)步,将求得vi到vj 的且中间顶点号不大于n-1的最短路径,这必是从vi到vj的最短路径。

图g中所有顶点偶对vi、vj间的最短路径长度对应一个n阶方阵D。在上述n+1步中,D的值不断变化,对应一个n阶方阵序列。

定义

n阶方阵序列:D-1, D0, D1, D2, …Dn-1

其中 :

显然,Dn-1中为所有顶点偶对vi、vj间的最终最短路径长度。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

#define MAX_VERTEX_NUM 20//最多顶点个数
#define INFINITY 32768//表示极大值
#define ElemType int

typedef struct Graph{
    int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//二维数组存储邻接矩阵
    int vexnum;//顶点数
}Graph;
/*矩阵建图/网*/
//图:0表示没有边,1表示有边
//网:0表示没有边,非0表示边上权值
void CreateMatrix(Graph * G){//一般从下标0开始存图
    cout << "请输入矩阵:" << endl;
    int x;
    for(int i=0;i<G->vexnum;++i){
        G->visited[i] = 0;
        for(int j=0;j<G->vexnum;++j){
            cin >> x;
            if(x) G->arcs[i][j] = x;
            else G->arcs[i][j] = INFINITY;
            if(i==j) G->arcs[i][j] = 0;
        }
    }
}

typedef struct{
    ElemType elem[MAX_VERTEX_NUM];//线性表占用的数组空间
    int last;//记录线性表中最后一个元素在数组elem[]中的位置(下标值),空表置为-1
}SeqList;
void AddTail(SeqList *L,ElemType e){//在顺序表末尾插入一个元素e
    L->last++;
    L->elem[L->last] = e;
}
void InitList(SeqList * L){
    L->last = -1;
}
SeqList JoinList(SeqList L1,SeqList L2){
    for(int i=0;i<=L2.last;++i)
        L1.elem[++L1.last] = L2.elem[i];
    return L1;
}


void Floyd(Graph G,int dist[MAX_VERTEX_NUM][MAX_VERTEX_NUM],SeqList path[MAX_VERTEX_NUM][MAX_VERTEX_NUM]){
    //path[i][j]为vi到vj的当前最短路径
    //dist[i][j]为vi到vj的当前最短路径长度
    for(int i=0;i<G.vexnum;++i){//初始化dist[i][j]和path[i][j]
        for(int j=0;j<G.vexnum;++j){
            InitList(&path[i][j]);
            dist[i][j] = G.arcs[i][j];
            if(dist[i][j]<INFINITY){
                AddTail(&path[i][j],i);
                AddTail(&path[i][j],j);
            }
        }
    }
    for(int k=0;k<G.vexnum;++k){
        for(int i=0;i<G.vexnum;++i){
            for(int j=0;j<G.vexnum;++j){
                if(dist[i][k]+dist[k][j]<dist[i][j]){
                    dist[i][j] = dist[i][k]+dist[k][j];
                    path[i][j] = JoinList(path[i][k],path[k][j]);
                }
            }
        }
    }
}

int main()
{
    Graph G;
    SeqList path[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    int dist[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    cout << "请输入顶点数:";
    cin >> G.vexnum;
    CreateMatrix(&G);

    Floyd(G,dist,path);

    for(int i=0;i<G.vexnum;++i){
        for(int j=0;j<G.vexnum;++j){
            cout << "从" << i << "到" << j << ":";
            for(int k=0;k<=path[i][j].last;++k)
                cout << path[i][j].elem[k] << " ";
            cout << endl;
            if(dist[i][j]==INFINITY) cout << -1 << endl;
            else cout << "其最短路径长度为" << dist[i][j] << endl;
        }
    }

    return 0;
}

8586bd99a6bcd30579272fb9c1e75f60.png

返回目录:

Chilan Yu:《数据结构》目录链接​zhuanlan.zhihu.com
16500f0d365c95a84f59b2d2bd13ca8c.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值