ACM总结二十二

最短路径算法

边带有权值的图称为带权图。边的权值可以理解为两点之间的距离。一张图中任意两点间会有不同的路径相连。最短路径就是指连接两点的这些路径中最短的一条。

一、求出最短路径的长度

以下没有特别说明的话,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

For (k = 1; k
<= n; k++)

For (i = 1; i <= n; i++)

    For (j = 1; j <= n; j++)

If (dis[i][j] >dis[i][k] + dis[k][j])

dis[i][j] = dis[i][k] + dis[k][j];

算法结束:dis[i][j]得出的就是从i到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的前驱节点,用来输出路径。

我们把点分为两类,一类是已确定最短路径的点,称为“白点”,另一类是未确定最短路径的点,称为“蓝点”。如果我们要求出一个点的最短路径,就是把这个点由蓝点变为白点。从起点到蓝点的最短路径上的中转点在这个时刻只能是白点。

Dijkstra的算法思想,就是一开始将起点到起点的距离标记为0,而后进行n次循环,每次找出一个到起点距离dis[u]最短的点u,将它从蓝点变为白点。随后枚举所有的蓝点vi,如果以此白点为中转到达蓝点vi的路径dis[u]+w[u][vi]更短的话,这将它作为vi的“更短路径”dis[vi](此时还不确定是不是vi的最短路径)。

就这样,我们每找到一个白点,就尝试着用它修改其他所有的蓝点。中转点先于终点变成白点,故每一个终点一定能够被它的最后一个中转点所修改,而求得最短路径。

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算法的一种队列实现,减少了不必要的冗余计算。

主要思想是:

初始时将起点加入队列。每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队。直到队列为空时算法结束。

这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法。、

SPFA 在形式上和广度优先搜索非常类似,不同的是广度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是说一个点修改过其它的点之后,过了一段时间可能会获得更短的路径,于是再次用来修改其它的点,这样反复进行下去。

算法时间复杂度:O(kE),E是边数。K是常数,平均值为2。

猜你喜欢

转载自blog.csdn.net/qq_43515378/article/details/90552730