图的应用:最短路径

一、最短路径简述

1、应用

从一个城市A到另一个城市B有很多的交通路线可以走,如果假设这些交通线路构成了一个无向图,则求从A到B的最短路径,可以用 广度优先算法 得到 这个 无向图 的 广度优先生成树,然后,从生成树中 找到 从A到B的路径 即为 从A到B的最短路径。

但是,现实世界远远没有这么简单,这些交通线路更像是一个 带权有向网,要求 从A到B的最短路径,需要考虑各个边上的权值。这个问题 可以用 最短路径算法 解决。

二、最短路径算法

1、求从某一个源点到其余各顶点的最短路径:迪杰斯特拉算法

迪杰斯特拉算法 的 核心思想是:
对于网络N=(V,E),将N中的顶点分成两组:
第一组S:已求出的最短路径的终点集合(初始时只包含源点v0)。
第二组V-S:尚未求出最短路径的终点集合(初始时为V-{v0})。
算法将按各顶点到v0间最短路径长度递增的次序,逐个将集合V-S中的顶点加入到集合S中去。在这个过程中,总保持从v0到S中顶点的距离不大于到V-S中顶点的距离。
理论:按照这种思路,则从v0到V-S中定点的最短路径:要么为<v0,v>,要么为中间经过S中顶点的一条路径。

反证:如果<v0,v>最短路径中历经的一个顶点不在S中,则说明存在一个顶点P,其到v0的距离 小于<v0,v>,这与S中顶点最短路径 总小于等于 V-S中最短路径 这一前提假设相违背,因此,我们可知,上述理论成立。

迪杰斯特拉算法 伪代码

//带权有向网 用 邻接矩阵 形式存储
//算法实现引入以下几个数据结构:
//S[i]为boolvalue,表示顶点i是否找到最短路径
//Path[i]代表v~0~到i的最短路径中,i的直接前驱结点;如果v~0~到i没有通路,Path[i]=-1
//D[i]表示i结点的最短路径长度
void ShortestPath_DIJ(AMGraph G,int v0){
  //首先进行初始化 S[i],Path[i],D[i]
  n=G.vexnum; //结点个数
  for(i=0;i<n;++i){
    S[i]=false;
    D[i] = G.arcs[v0][i]; //初始化最短路径为 v0d到i的距离
    if(D[i] < MAXInt){Path = v0;}
    else{Path = -1;}
  }
  S[v0] = true;
  D[v0] = 0;
  //从n-1个结点中,依次找出最短路径,加到S中
  for(i=1;i<n;++i){
    min = MAXInt;
    for(w=0;w<n;++w){
      if(D[w]<min && !S[w]){
        if(D[w]<min){
          min=D[w];
          v=w; //最小路径 结点
        }
      }
    }
    S[v] = true;
    //将结点加入到S中后,更新V-S中结点最短路径值
    for(i=0;i<n;++i){
      if(!S[i] && G.arcs[v][i] + D[v] < D[i]){
        D[i]= G.arcs[v][i] + D[v];
        Path[i] = v;
      }
    }
  }
}

总结:
1、算法在寻找n-1个顶点的最短路径时,有一个for(n-1),在这个for循环中,每次找一个最短路径,需要遍历所有的结点,因此,迪杰斯特拉算法执行的时间复杂度为O(n2)。即便将图采用邻接表的方式进行存储,算法时间复杂度依然为O(n2);
2、在实际中,人们往往想求得是从A到B的最短路径,即便如此,这个问题和
求源点到其它顶点的最短路径 一样复杂,也需要利用 迪杰斯特拉算法 实现,其时间复杂度仍然为O(n2);
3、在求得v0到各个顶点的最短路径后,要想找出vi的最短路径,则只需要追溯Path数组即可:vj=Path[vi]; vf=Path[vj]; v0=Path[vf];

2、每一对顶点之间的最短路径:佛洛依德算法

弗洛伊德算法 核心思想:
结点vi和vj之间的最短路径,最开始为G.arcs[vi][vj];
向vi和vj中逐个加入其它顶点,判断原来的最短路径和加入顶点的最短路径(<vi,…,vk> +<vk,…,vj>) 哪个更短,取更短的那个路径。
按照上述思路,求每对顶点间的最短路径。

佛洛依德算法伪代码

void ShortestPath_Floyd(AMGraph G){
  //初始化各个顶点对间的最短路径,以及Path
  for(i=0;i<G.vexnum;++i){
    for(j=0;j<G.vexnum;++j){
      D[i][j] = G.arcs[i][j]; //初始化最短路径
      if(D[i][j] < MaxInt && i != j){Path[i][j] = i;}
      else{Path[i][j] = -1;}
    }
    //逐个加入顶点,求解各个点对 的最短路径
    for(k=0;k<G.vexnum;++k){
      for(i=0;i<G.vexnum;++i){
        for(j=0;j<G.vexnum;++j){
          if(G[i][k] + G[k][j] < D[i][j]){
            D[i][j] = G[i][k] + G[k][j];
            Path[i][j] = Path[k][j];
          }
        }
      }
    }
  }    

总结:
1、佛洛依德算法的时间复杂度为O(n3);
2、假设要求D[1][2]的最短路径:Path[1][2]=3;Path[1][3]=4;Path[1][4]=1;则D[1][2]的最短路径为:1->4->3->2;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sarah ฅʕ•̫͡•ʔฅ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值