探求Floyd算法的动态规划本质

Floyd–Warshall(简称Floyd算法)是一种著名的解决任意两点间的最短路径(All Paris Shortest Paths,APSP)的算法。从表面上粗看,Floyd算法是一个非常简单的三重循环,而且纯粹的Floyd算法的循环体内的语句也十分简洁。我认为, 正是由于“Floyd算法是一种动态规划(Dynamic Programming)算法”的本质,才导致了Floyd算法如此精妙。因此,这里我将从Floyd算法的状态定义、动态转移方程以及滚动数组等重要方 面,来简单剖析一下图论中这一重要的基于动态规划的算法——Floyd算法。

在动态规划算法中,处于首要位置、且也是核心理念之一的就是状态的定义。在这里,把d[k][i][j]定义成:

“只能使用第1号到第k号点作为中间媒介时,点i到点j之间的最短路径长度。”

图中共有n个点,标号从1开始到n。因此,在这里,k可以认为是动态规划算法在进行时的一种层次,或者称为“松弛操作”。d[1][i][j]表示 只使用1号点作为中间媒介时,点i到点j之间的最短路径长度;d[2][i][j]表示使用1号点到2号点中的所有点作为中间媒介时,点i到点j之间的最 短路径长度;d[n-1][i][j]表示使用1号点到(n-1)号点中的所有点作为中间媒介时,点i到点j之间的最短路径长度d[n][i][j]表示 使用1号到n号点时,点i到点j之间的最短路径长度。有了状态的定义之后,就可以根据动态规划思想来构建动态转移方程。

动态转移的基本思想可以认为是建立起某一状态之前状态的一种转移表示。 按照前面的定义,d[k][i][j]是一种使用1号到k号点的状态,可以想办法把这个状态通过动态转移,规约到使用1号到(k-1)号的状态,即 d[k-1][i][j]。对于d[k][i][j](即使用1号到k号点中的所有点作为中间媒介时,i和j之间的最短路径),可以分为两种情况: (1)i到j的最短路不经过k;(2)i到j的最短路经过了k。不经过点k的最短路情况下,d[k][i][j]=d[k-1][i][j]。经过点k的 最短路情况下,d[k][i][j]=d[k-1][i][k]+d[k-1][k][j]。因此,综合上述两种情况,便可以得到Floyd算法的动态转 移方程:

d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k]+d[k-1][k][j])(k,i,j∈[1,n]

最后,d[n][i][j]就是所要求的图中所有的两点之间的最短路径的长度。在这里,需要注意上述动态转移方程的初始(边界)条件,即d[0] [i][j]=w(i, j),也就是说在不使用任何点的情况下(“松弛操作”的最初),两点之间最短路径的长度就是两点之间边的权值(若两点之间没有边,则权值为INF,且我比 较偏向在Floyd算法中把图用邻接矩阵的数据结构来表示,因为便于操作)。当然,还有d[i][i]=0i∈[1,n]

这样我们就可以编写出最为初步的Floyd算法代码:


1

2

3

4

5

6

7

8

9

10

11

12

void floyd_original() {

    for(int i = 1; i <= n; i++)

        for(int j = 1; j <= n; j++)

            d[0][i][j] = graph[i][j];

    for(int k = 1; k <= n; k++) {

        for(int i = 1; i <= n; i++) {

            for(int j = 1; j <= n; j++) {

                d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k] + d[k-1][k][j]);

            }

        }

    }

}

几乎所有介绍动态规划中最为著名的“0/1背包”问题的算法书籍中,都会进一步介绍利用滚动数组的技巧来进一步减少算法的空间复杂度,使得0/1背 包只需要使用一维数组就可以求得最优解。而在各种资料中,最为常见的Floyd算法也都是用了二维数组来表示状态。那么,在Floyd算法中,是如何运用 滚动数组的呢?

再次观察动态转移方程d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k]+d[k-1][k][j]),可以发现每一个第k阶段的状态(d[k][i][j]),所依赖的都是前一阶段(即第k-1阶 段)的状态(如d[k-1][i][j],d[k-1][i][k]和d[k-1][k][j])。

上图描述了在前面最初试的Floyd算法中,计算状态d[k][i][j]时,d[k-1][][]和d[k][][]这两个二维数组的情况 (d[k-1][][]表示第k-1阶段时,图中两点之间最短路径长度的二维矩阵;d[k][][]表示第k阶段时,图中两点之间最短路径长度的二维矩 阵)。红色带有箭头的有向线段指示了规划方向。灰色表示已经算过的数组元素,白色代表还未算过的元素。由于d[k-1][][]和d[k][][]是两个 相互独立的二维数组,因此利用d[k-1][i][j],d[k-1][i][k]和d[k-1][k][j](皆处于上方的二维数组中)来计算d[k] [i][j]时没有任何问题。

那如何利用一个二维数组来实现滚动数组,以减小空间复杂度呢?

上图是使用滚动数组,在第k阶段,计算d[i][j]时的情况。此时,由于使用d[][]这个二维数组作为滚动数组,在各个阶段的计算中被重复使 用,因此数组中表示阶段的那一维也被取消了。在这图中,白色的格子,代表最新被计算过的元素(即第k阶段的新值),而灰色的格子中的元素值,其实保存的还 是上一阶段(即第k-1阶段)的旧值。因此,在新的d[i][j]还未被计算出来时,d[i][j]中保存的值其实就对应之前没有用滚动数组时d[k- 1][i][j]的值。此时,动态转移方程在隐藏掉阶段索引后就变为:

d[i][j] = min(d[i][j], d[i][k]+d[k][j])(k,i,j∈[1,n]

赋值号左侧d[i][j]就是我们要计算的第k阶段是i和j之间的最短路径长度。在这里,需要确保赋值号右侧的d[i][j], d[i][k]和d[k][j]的值是上一阶段(k-1阶段)的值。前面已经分析过了,在新的d[i][j]算出之前,d[i][j]元素保留的值的确就 是上一阶段的旧值。但至于d[i][k]和d[k][j]呢?我们无法确定这两个元素是落在白色区域(新值)还是灰色区域(旧值)。好在有这样一条重要的 性质,dp[k-1][i][k]和dp[k-1][k][j]是不会在第k阶段改变大小的。也就是说,凡是和k节点相连的边,在第k阶段的值都不会变。 如何简单证明呢?我们可以把j=k代入之前的d[k][i][j]=min(d[k-1][i][j], d[k-1][i][k]+d[k-1][k][j])方程中,即:

d[k][i][k]

= min(d[k-1][i][k], d[k-1][i][k]+d[k-1][k][k])

= min(d[k-1][i][k], d[k-1][i][k]+0)

= d[k-1][i][k]

也就是说在第k-1阶段和第k阶段,点i和点k之间的最短路径长度是不变的。相同可以证明,在这两个阶段中,点k和点j之间的的最短路径长度也是不 变的。因此,对于使用滚动数组的转移方程d[i][j] = min(d[i][j], d[i][k]+d[k][j])来说,赋值号右侧的d[i][j], d[i][k]和d[k][j]的值都是上一阶段(k-1阶段)的值,可以放心地被用来计算第k阶段时d[i][j]的值。

利用滚动数组改写后的Floyd算法代码如下:


1

2

3

4

5

6

void floyd() {

    for(int k = 1; k <= n; k++)

        for(int i = 1; i <= n; i++)

            for(int j = 1; j <= n; j++)

                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

}

因此,通过这篇文章的分析,我们可以发现,Floyd算法的的确确是一种典型的动态规划算法;理解Floyd算法,也可以帮助我们进一步理解动态规划思想。

转载:http://www.cnblogs.com/chenying99/p/3932877.html

时间: 2024-10-11 10:35:23

探求Floyd算法的动态规划本质的相关文章

Floyd 算法求多源最短路径

Floyd算法: Floyd算法用来找出每对顶点之间的最短距离,它对图的要求是,既可以是无向图也可以是有向图,边权可以为负,但是不能存在负环. 基本算法: Floyd算法基于动态规划的思想,以 u 到 v 的最短路径至少经过前 k 个点为转移状态进行计算,通过 k 的增加达到寻找最短路径的目的.当 k 增加 1 时,最短路径要么不边,如果改变,必经过第 k 各点,也就是说当起点 u 到第 k 个点的最短距离加上第 k 个点到终点 v 的最短路径小于不经过第 k 个节点的最优最短路经长度的时候更新

最短路径Dijkstra算法和Floyd算法整理、

转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径—Dijkstra算法和Floyd算法 Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法 本篇名言:"希望是厄运的忠实的姐妹. --普希金" 我们继续来看下数据结构图中的一个算法,这个算法来自图灵奖得主. 1.  Floyd算法介绍 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名.注意这个可不是心理学的那个弗洛伊德. 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径

hihocoder1089 Floyd算法

题目链接:http://hihocoder.com/problemset/problem/1089 算法描述: floyd算法是求解图中任意两点最短路的经典算法,复杂度为O(n^3).虽然我们完全可以用n次dijkstra算法来求任意两点的最短路,复杂度也是O(N^3),但如果有一个算法只需要5行代码就可以完成我们想做的事情,我们有什么理由不用它?! floyd算法主要用了动态规划的思想: 设d[i][j]表示i到j的最短路径的长度, 那么我们可以这样来求解d[i][j]: (1)首先,i到j的

最短路径—Dijkstra算法和Floyd算法

Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径.(单源最短路径) 2.算法

Dijkstra算法,Floyd算法以及A*算法

Dijkstra算法 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. Floyd算法 Floyd算法是一个经典的动态规划算法.用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径.从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在) 从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点

Floyd算法思想

Floyd算法是一个经典的动态规划算法.用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径.从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在),floyd算法加入了这个概念 Ak(i,j):表示从i到j中途不经过索引比k大的点的最短路径. 这个限制的重要之处在于,它将最短路径的概念做了限制,使得该限制有机会满足迭代关系,这个迭代关系就在于研究:假设Ak(i,j)已知,是否可以借此推导出Ak-1(i,j). 假设我现在要得到Ak(i

多源最短路径Floyd算法

多源最短路径是求图中任意两点间的最短路,采用动态规划算法,也称为Floyd算法.将顶点编号为0,1,2...n-1首先定义dis[i][j][k]为顶点 i 到 j 的最短路径,且这条路径只经过最大编号不超过k的顶点.于是我们最终要求的是dis[i][j][n-1].状态转移方程如下: dis[i][j][k]=min{dis[i][j][k-1],dis[i][k][k-1]+dis[k][j][k-1]}; 状态转移方程的解释:在计算dis[i][j][k]的时候,我们考虑 i 到 j 是否

最短路径—Floyd算法

Floyd算法 所有顶点对之间的最短路径问题是:对于给定的有向网络G=(V,E),要对G中任意两个顶点v,w(v不等于w),找出v到w的最短路径.当然我们可以n次执行DIJKSTRA算法,用FLOYD则更为直接,两种方法的时间复杂度都是一样的. 1.定义概览 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包.Floyd-Warshall算法的时间复杂度