算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法

前言

    前面介绍了单源最短路径问题,本文是介绍所有节点对的最短路径问题,首先我们会想到用前面所介绍的知识来求解该问题,根据不同类型的图可以用一下几种方法求解:

  1. 若无权重的图,则可以使用BFS,时间复杂度是;
  2. 若为非负权重边的图,则可以使用Dijkstra算法,不同的优先队列实现得到不同的时间复杂度:①线性数组,。②二叉堆,,在稀疏图的情况下是一个较大的改进。③斐波那契堆,;
  3. 若含有负权重边的图,则可以使用Bellman-Ford算法,稠密的情况下时间复杂度是为
  为了降低时间复杂度,我们下面采用 Floyd-Warshall 算法和 Johnson 算法进行求解。

Floyd-Warshall算法

    该算法的原理是动态规划,并且图的表示方式是邻接表矩阵。根据动态规划的求解步骤:

  1. 分析最优解结构;
  2. 递归定义最优解的值;
  3. 自底向上计算最优解的值;
  4. 根据计算出的最优解的值构造最优解;

    使用该算法是可以存在负权值的边,但不能存在权值为负值的环路。在求解之前先介绍基本概念:

    中间节点:简单路径的中间节点是指路径上除节点和节点之外的任意节点,也就是处于集合中的节点。

Floyd-Warshall算法的求解步骤:

最短路径结构(最优解结构)

    假定图的所有节点为,考虑其中一个子集,的某个整数。对任意节点,考虑从节点到节点的所有中间节点均取自集合的路径,并且设为其中权重最小的路径。Floyd-Warshall算法利用路径和从节点到节点之间中间节点均取自集合的最短路径之间的关系。该关系依赖于节点是否是路径上的一个中间节点。

  1. 若节点不是路径的中间节点,则路径上的中间节点都属于集合。因此,从节点到节点之间中间节点均取自集合的一条最短路径也是从节点到节点的所有中间节点均取自集合的一条最短路径,即:,其中表示从节点到节点的所有中间节点均取自集合的一条最短路径的权重。
  2. 若节点是路径的中间节点,则将路径分解为,因此,从节点到节点之间中间节点均取自集合的一条最短路径,,是从节点到节点之间中间节点均取自集合的一条最短路径,即:

最短路径的一个递归解(递归定义最优解的值)

    根据上面的分析可得一个递归解:


自底向上计算最短路径的权重

    根据递归公式计算出最短路径权重。计算伪代码如下:

FLOYD-WARSHALL(W)  
{  
    n = W.rows;  
    D(0) = W;  
    for(k = 1;k <= n;++k){  
        let D(k) = d[i,j](k) be a new n*n matrix;  
        for i = 1 to n  
            for j = 1 to n  
                d[i,j](k) = min(d[i,j](k-1), d[i,k](k-1)+ d[k,j](k-1) )  
    }  
    return D(n);  
}

构造一条最短路径

    我们选择在计算最短路径权值矩阵的,同时计算前驱矩阵,我们定义从节点到节点之间中间节点均取自集合的最短路径上的前驱节点。的递归定义跟最短路径权重类似。

时:


时:


      计算过程只是在计算最短路径权重的基础上加上计算前驱矩阵的算法即可。伪代码如下:

FLOYD-WARSHALL(W)  
{  
    n = W.rows;  
    D(0) = W;
	TT(0) = 初始值
    for(k = 1;k <= n;++k){  
        let D(k) = d[i,j](k) be a new n*n matrix;  
		let TT(k) = π[i,j](k) be a new n*n matrix;
        for i = 1 to n  
            for j = 1 to n  
                d[i,j](k) = min(d[i,j](k-1), d[i,k](k-1)+ d[k,j](k-1) )  
				if d[i,j](k)== d[i,j](k-1)
					π[i,j](k) = π[i,j](k-1)
				else π[i,j](k) = π[k,j](k-1)
    }  
    return D(n),TT(n);  
}

Johnson算法

       Johnson算法主要用于求稀疏图上的所有节点对的最短路径。其主体思想是利用重新赋予权值的方法把一个原问题带负权的图转化为权值非负的图。然后再对每个节点使用一次Dijkstra算法以求出所有节点对的最短路径。时间复杂度;

重新赋予权值必须满足一下两个条件:

  1. 对于所有节点对,一条路径是在使用权值函数时从节点到节点的一条最短路径,当且仅当是在权值函数时从节点到节点的一条最短路径。
  2. 对于所有的边,新的权值为非负值。

     重新赋予权值不会改变最短路径,对于每条边,权值函数的关系为:,其中为新添加节点到节点的最短路径;

Johnson算法的步骤:

  1. 在带有权重的有向原始图添加一个新节点使其成为新的图,其中对于原图的所有节点,使其到新节点的边权值为0,即
  2. Bellman-Ford算法检查所输入的图是否包含权值为负的环路,若有打印不存在最短路径并退出,否则继续;
  3. Bellman-Ford算法计算新节点到所有节点的最短路径,所计算的节点最短路径就是的值;
  4. 更新所有边的权值,即计算
  5. 对已更新权值的图的每个节点进行一次Dijkstra算法,求出所有节点对的最短路径;

举例说明Johnson算法的实现步骤:若要计算图的所有节点对的最短路径;

算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法_第1张图片

    若是直接按照Bellman-Ford算法计算某个节点的最短路径,则如下图所示:

算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法_第2张图片

    根据Johnson算法的步骤,首先添加新节点使其成为新图,如下图所示:

算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法_第3张图片

    对扩展图进行一次Bellman-Ford算法处理,得到以为源节点的最短路径,如下图所示:

算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法_第4张图片

    根据上一步骤以为源节点的最短路径更新边的权值,按照公式:进行更新,如下图所示:

算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法_第5张图片

    根据上一步骤更新边的权值,得到新权值的图,如下图所示:

算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法_第6张图片

    对更新权值后的图的每个节点进行一次Dijkstra算法,即可求得所有节点对的最短路径;由于只是重复的过程,下图只给出其中一个节点的求解图,其他节点这里就不给出了;提示:这里节点里面标记的权值是,与原图最短路径的关系为:

算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法_第7张图片

你可能感兴趣的:(Johnson算法,所有结点对的最短路径,图算法)