最短路径算法

根据图的概念,最短路径主要有四种算法,但是当有负权值的时候,有些算法是不适用的,下面就来介绍一下这四种算法:

以下没有特别说明的话,dis[u][v]表示从u到v最短路径长度,w[u][v]表示连接u,v的边的长度。

1.Floyed-Warshall算法 O(N3) 
简称Floyed(弗洛伊德)算法,是最简单的最短路径算法,可以计算图中任意两点间的最短路径。Floyed的时间复杂度是O (N3),适用于出现负边权的情况。

初始化:点u、v如果有边相连,则dis[u][v]=w[u][v]。
如果不相连则dis[u][v]=0x7fffffff


Floyed算法变形:
如果是一个没有边权的图,把相连的两点间的距离设为dis[i][j]=true,不相连的两点设为dis[i][j]=false;

For (k = 1; k <= n; k++)
  For (i = 1; i <= n; i++)
    For (j = 1; j <= n; j++)
    dis[i][j] = dis[i][j] || (dis[i][k] && dis[k][j]);
       用这个办法可以判断一张图中的两点是否相连。

 2.Dijkstra算法O (N2)
用来计算从一个点到其他所有点的最短路径的算法,是一种单源最短路径算法。也就是说,只能计算起点只有一个的情况。
Dijkstra的时间复杂度是O (N2),它不能处理存在负边权的情况。
算法描述:
      

设起点为s,dis[v]表示从s到v的最短路径,pre[v]为v的前驱节点,用来输出路径。
       a)初始化:dis[v]=∞(v≠s); dis[s]=0; pre[s]=0; 
       b)For (i = 1; i <= n ; i++)
            1.在没有被访问过的点中找一个顶点u使得dis[u]是最小的。
            2.u标记为已确定最短路径
            3.For 与u相连的每个未确定最短路径的顶点v
              if  (dis[u]+w[u][v] < dis[v]) 
               {
                  dis[v] = dis[u] + w[u][v];
                  pre[v] = u;
               }
        c)算法结束:dis[v]为s到v的最短距离;pre[v]为v的前驱节点,用来输出路径。

3.Bellman-Ford算法O(NE)
简称Ford(福特)算法,同样是用来计算从一个点到其他所有点的最短路径的算法,也是一种单源最短路径算法。
能够处理存在负边权的情况,但无法处理存在负权回路的情况(下文会有详细说明)。
算法时间复杂度:O(NE),N是顶点数,E是边数。
算法实现:
 

设s为起点,dis[v]即为s到v的最短距离,pre[v]为v前驱。w[j]是边j的长度,且j连接u、v。
初始化:dis[s]=0,dis[v]=∞(v≠s),pre[s]=0
For (i = 1; i <= n-1; i++)
For (j = 1; j <= E; j++)         //注意要枚举所有边,不能枚举点。
   if (dis[u]+w[j]<dis[v])          //u、v分别是这条边连接的两个点。
    {
       dis[v] =dis[u] + w[j];
       pre[v] = u;
  }

4、SPFA算法O(kE)
SPFA是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算。
主要思想是:
初始时将起点加入队列。每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队。直到队列为空时算法结束。

算法的实现:

dis[i]记录从起点s到i的最短路径,w[i][j]记录连接i,j的边的长度。pre[v]记录前趋。
    team[1..n]为队列,头指针head,尾指针tail。
    布尔数组exist[1..n]记录一个点是否现在存在在队列中。
    初始化:dis[s]=0,dis[v]=∞(v≠s),memset(exist,false,sizeof(exist));
    起点入队team[1]=s; head=0; tail=1;exist[s]=true;
    do
    { 
    1、头指针向下移一位,取出指向的点u。
    2、exist[u]=false;已被取出了队列
    3、for与u相连的所有点v          //注意不要去枚举所有点,用数组模拟邻接表存储

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值