欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【笔记】每一对顶点间的最短路径

程序员文章站 2024-03-17 10:10:10
...

1.每一对顶点间的最短路径

  如果要计算每一对顶点之间的最短路径,需每次以一个顶点为出发点,将迪杰斯特拉算法重复执行n次,就可以得到每一对顶点的最短路径,总的时间复杂度为O(n3)。如果采用弗洛伊德算法,虽然时间复杂度也是O(n3),但是形式更简单。

2.弗洛伊德算法

   基本算法思想:假设求顶点vi到顶点vj的最短路径,如果从顶点vivj有弧,则从vivj存在一条成都为arc[i][j]的路径,但该路径不一定是vivj的最短路径,还需要进行n次试探。首先需要从顶点v0开始,如果有路径(vi,v0,vj)存在,则比较路径(vi,vj)(vi,v0,vj),选择两者中最短的一个且中间顶点的序号不大于0的最短路径。
  假如在路径上再增加一个顶点v1,如果(vi,,v1)(v1,,vj)分别是当前找到的中间顶点的序号不大于0 的最短路径,那么(vi,v1vj)就有可能是从vivj的中间顶点的序号不大于1的最短路径。把它和已经得到的从vivj中间顶点序号不大于0的最短路径相比较,从中选择中间顶点的序号不大于1的最短路径之后,再增加1个顶点v2,继续进行试探。
  依此类推,一般情况下, 若(vi,,vk)(vk,,vj)分别是从vivk和从vkvj的中间顶点的序号不大于k-1的最短路径,则将(vi,vkvj)和已经得到的从vivj且中间顶点序号不大于k-1的最短路径相比较,其长度较短者就是从vivj的中间顶点序号不大于k的最短路径。经过n次比较,可以得到从vivk的中间顶点序号不大于n-1的最短路径。依照这种方法,可以得到各个顶点之间的最短路径。

  假设采用邻接矩阵存储带权有向图G,则各个顶点之间的最短路径可以保存在一个n阶方阵D中,每次求出的最短路径可以用矩阵表示为D1D0D1D2Dn1。其中,D1[i][j]=G.arc[i][j].adjDk[i][j]=Min{Dk1[i][j],Dk1[i][k]|0kn1}。其中,Dk[i][j]即为从顶点vivk的最短路径长度。

3.弗洛伊德算法的实现

  • 类型定义
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>
#define INFINITY 65535          /*定义一个无限大的值*/
#define MaxSize 50              /*最大顶点个数*/
typedef char VertexType[4];
typedef char InfoPtr;
typedef int VRType;
typedef enum{DG,DN,UG,UN}GraphKind;     /*图的类型:有向图、有向网、无向图和无向网*/
typedef int PathMatrix[MaxSize][MaxSize][MaxSize];  /*定义一个保存最短路径的三维数组*/
typedef int ShortPathLength[MaxSize][MaxSize];      /*定义一个保存从顶点v到顶点w的最短距离的数组*/
typedef struct
{
    VRType adj;             /*对于无权图,用1表示相邻,0表示不相邻;对于带权图,存储权值*/
    InfoPtr *info;              /*与弧或边的相关信息*/
}ArcNode,AdjMatrix[MaxSize][MaxSize];
typedef struct                  /*图的类型定义*/
{
    VertexType vex[MaxSize];    /*用于存储顶点*/
    AdjMatrix arc;              /*邻接矩阵,存储边或弧的信息*/
    int vexnum,arcnum;          /*顶点数和边(弧)的数目*/
    GraphKind kind;             /*图的类型*/
}MGraph;
typedef struct                  /*添加一个存储网的行、列和权值的类型定义*/
{
    int row;
    int col;
    int weight;
}GNode;
  • Floyd算法
void Floyd(MGraph N,PathMatrix path,ShortPathLength dist)
/*用Floyd算法求有向网N的各顶点v和w的最短路径,
其中path[v][w][u]表示u是从v到w当前求得最短路径上的顶点*/
{
    int u,v,w,i;
    for(v=0;v<N.vexnum;v++)                 /*初始化数组path和dist*/
        for(w=0;w<N.vexnum;w++)
        {
            dist[v][w]=N.arc[v][w].adj;     /*初始时,顶点v到顶点w的最短路径为v到w的弧的权值*/
            for(u=0;u<N.vexnum;u++)
                path[v][w][u]=0;            /*路径矩阵初始化为零*/
            if(dist[v][w]<INFINITY)          /*如果v到w有路径,则由v到w的路径经过v和w两点*/
            {
                path[v][w][u]=1;
                path[v][w][w]=1;
            }
        }
    for(u=0;u<N.vexnum;u++)
        for(v=0;v<N.vexnum;v++)
            for(w=0;w<N.vexnum;w++)
                if(dist[v][u]<INFINITY&&dist[u][w]<INFINITY&&dist[v][u]+dist[u][w]<dist[v][w])
                /*从v经u到w的一条路径为当前最短的路径*/
                {
                    dist[v][w]=dist[v][u]+dist[u][w];   /*更新v到w的最短路径*/
                    for(i=0;i<N.vexnum;i++)             /*从v到w的路径经过从v到u和从u到w的所有路径*/
                        path[v][w][i]=path[v][u][i]||path[u][w][i];
                }
}
  • 邻接矩阵创建有向网
void CreateGraph(MGraph *N,GNode *value,int vnum,int arcnum,VertexType *ch)
/*采用邻接矩阵表示法创建有向网N*/
{
    int i,j,k;
    N->vexnum=vnum;
    N->arcnum=arcnum;
    for(i=0;i<vnum;i++)             /*将各个顶点赋值给vex域*/
        strcpy(N->vex[i],ch[i]);
    for(i=0;i<N->vexnum;i++)            /*初始化邻接矩阵*/
        for(j=0;j<N->vexnum;j++)
        {
            N->arc[i][j].adj=INFINITY;
            N->arc[i][j].info=NULL; /*弧的信息初始化为空*/
        }
    for(k=0;k<arcnum;k++)
    {
        i=value[k].row;
        j=value[k].col;
        N->arc[i][j].adj=value[k].weight;
    }

    N->kind=DN;                     /*图的类型为有向网*/
}
  • 输出图
void DisplayGraph(MGraph N)
/*输出邻接矩阵存储表示的图N*/
{
    int i,j;
    printf("有向网具有%d个顶点%d条弧,顶点依次是: ",N.vexnum,N.arcnum);
    for(i=0;i<N.vexnum;++i)             /*输出网的顶点*/
        printf("%s ",N.vex[i]);
    printf("\n有向网N的:\n");               /*输出网N的弧*/
    printf("序号i=");
    for(i=0;i<N.vexnum;i++)
        printf("%8d",i);
    printf("\n");
    for(i=0;i<N.vexnum;i++)
    {
        printf("%8d",i);
        for(j=0;j<N.vexnum;j++)
            printf("%8d",N.arc[i][j].adj);
        printf("\n");
    }
}
  • 主程序
void main()
{
    int i,j,vnum=6,arcnum=8;
    MGraph N;
    GNode value[]={{0,2,15},{0,4,30},{0,5,100},{1,2,10},
    {2,3,50},{3,5,10},{4,3,20},{5,4,60}};
    VertexType ch[]={"v0","v1","v2","v3","v4","v5"};
    PathMatrix path;                        /*用二维数组存放最短路径所经过的顶点*/
    ShortPathLength dist;                   /*用一维数组存放最短路径长度*/
    CreateGraph(&N,value,vnum,arcnum,ch); /*创建有向网N*/
    DisplayGraph(N);                        /*输出有向网N*/
    Floyd(N,path,dist);
    for(i=0;i<N.vexnum;i++)
    {
        for(j=i+1;j<N.vexnum;j++)
        printf("%s到%s的最短路径长度为:%d\n",N.vex[i],N.vex[j],dist[i][j]);
    }
}
  • 测试结果


【笔记】每一对顶点间的最短路径