码迷,mamicode.com
首页 > 其他好文 > 详细

Floyd求解最短路

时间:2017-10-20 21:32:56      阅读:267      评论:0      收藏:0      [点我收藏+]

标签:i++   idt   状态   动态规划   问题   循环   关系   刷新   ==   

Floyd算法适用于求解全源最短路、也就是能够求解任意两点间的最短路径并且是适用于含有负权边的图,但是含有负环则不行了!空间复杂度为O(n2)、时间复杂度为O(n3)。其具体的原理在百度能够找到很多,下面只说说我的理解,首先关键代码如下

///dp[i][j]表示从 i 点到 j 点的最短路径长度
///dp的值一开始就是储存原始图的邻接矩阵,将矩阵中没有连通的两点赋值为 INF

for(int k=1; k<=N; k++)///N代表N个顶点
    for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
            dp[i][j] = min(dp[i][j], dp[i][k]+dp[k][j]);

///最后dp中就存储了所有点间的最短距离

即枚举所有的点去作为中转点去松弛 i 和 j ,那考虑这样的一些问题

① 如果将最外层的 k 放在最内层,算法是否依旧正确?

答案是否定的,这里给出知乎上大佬们的回答作为参考==> Floyd算法为什么把k放在最外层?

简单点说就是如果 k 放在内层,那么有些 i、j 便被过早确定、而后面便不再进行松弛更新,来看一

个例子 共有四个节点 ,邻接矩阵如下

inf   inf   inf     1

inf   inf   inf    inf

inf    1    inf    inf

inf    3     1     inf

如果我们按k循环再最内层来计算, 

那么1,2节点的最短路径为 

min( dp[1][2], dp[1][3]+dp[3][1], dp[1][4]+dp[4][2]) = 4;

而且之后不再更新1,2节点的最短距, 过早确定!

然而实际上min( dp[1][2] ) = dp[1][4]+dp[4][3]+dp[3][2] = 3;

 

② 那么最外层的 k 的枚举顺序是否有影响?也就是我将 k 逆序枚举 或 k 打乱顺序枚举是否可行?

实际上不影响,对于枚举出来的每一个 k 而言,它需要依赖其他 k 吗?即 当前 k 需要 k-1 或 k+1或者其他一些值先算出来,才能保证当前 k 算出来的是最优的吗?不影响吧!实际上对于一副图来说,并没有什么点的顺序可言,在 Floyd 中 k 的顺序是输入顺序而已,打乱去枚举也没关系!

 

③ 它为什么是一个动态规划?不应该是贪心枚举全部所有点去贪心松弛么?

对的!它是每一次利用一个中转点去贪心松弛任意两点,每一次枚举完每一个 k 矩阵都应该会有一些点被刷新、变得更小,而每一次松弛都利用了上一次的最优结果,使得不用再重复计算。比如 当前枚举到 k-1 这个阶段,松弛完之后假设 dp[ii][jj] 变得更优了!而因为 dp[ii][jj] 更优了,下一次 k 的枚举就很有可能利用到被更新过的 dp[ii][jj] 去松弛其他点,避免了子问题重复计算,矩阵保存的就是当前这些最优 dp 状态,有动态规划的特点。上面的解释也能去解释 ② 。这只是我的个人感觉,若能指出其中错误,感激不尽!

 

 

第 ② 点的验证、以 HDU 2544

打乱顺序没问题、AC                                                       逆序也没问题、AC

技术分享   技术分享 

Floyd求解最短路

标签:i++   idt   状态   动态规划   问题   循环   关系   刷新   ==   

原文地址:http://www.cnblogs.com/Rubbishes/p/7701296.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!