每对顶点间的最短路径基本算法 --- 算法导论笔记

    之前有了单源最短路的基本算法,如果我们希望求每对顶点间的最短路径,可以把单源路径重复运用,也可以整体用动态规划的思路求解。

    提出两个动态规划的思路:按经过边的数量考虑(最多经过v-1条边),按增加一条边构造递推公式;按经过中间点的集合考虑(最多经过所有点),按增加一个点构造递推公式。

    其实我们可以感性地看出,后一种思路更优,因为它递推中隐含着边的数量(加一个点则最多经过的边的数量也加一)同时还具体到了哪些点(也就具体到了哪些边),也就是说这个操作过程更精细。最后事实上从复杂度上讲后一种也更优,前一O(V4)即使用了重复平方技术也只能到O(V3lgV),后一种O(V3)。

    给出伪码:

1:

SLOW-ALL-PAIRS-SHORTEST-PATHS(W)

n <- row[W]
L[1] <- W //only need to be L
for m <- 2 to n-1
  do L[m] <- EXTEND-SHORTEST-PATHS(L[m-1],W) // L <- EXTEND-SHORTEST-PATHS(L,W)
return L[n-1]  //L



EXTEND-SHORTEST-PATHS(L,W)

n <- rows[L]
let L' = (l'[i][j]) bean n*n matrix
for i <- 1 to n
  do for j <- 1 to n
       do l'[i][j] <- inf // infinity
         for k <- 1 to n
           do l'[i][j] <- min(l'[i][j],l[i][k] + w[k][j])
return L'


   这个稍作修改可以用来计算矩阵乘法,当然也可以用重复平方技术。


2(Floyd-Warshall):

FLOYD-WARSHALL(W)

n <- rows[W]
D[0] <- W //only need to be D
for k <- 1 to n
  do for i <- 1 to n
       do for j <- 1 to n
            do d[k][i][j] <- min(d[k-1][i][j],d[k-1][i][k] + d[k-1][k][j]) // d[i][j] <- min(d[i][j],d[i][k]+d[k][j])
return D[n] // D

    对于求每对顶点的最短距离而言,这个代码简单复杂度也可以。而每对顶点的最短路包含两个点之间的连通性,我们可以借此求解传递闭包,当然如果我们只要求解闭包而不考虑距离大小,可以用bit做数据结构。

    
    同时,重复用单源路径,在稀疏图上可以做到复杂度O(V2lgV+VE),即为Johnson算法,先用 Bellman-Ford检查负权回路,对于没有负权回路的运用重赋权技术,将权全部变为非负,就可以重复用较快的 Dijkstra。

    里面在算重赋权的时候,提出一个虚拟的点,到所有点有一个权为0的边,这样来算各个顶点映射的值保证非负(不证明了。。。)。这是一个很有意思的思想,我们可以借鉴用来处理其他一些问题。比如有很多网络上有很多点是服务器,其他点是用户,要找用户到最近服务器的距离,我们可以提出一个虚拟的点到所有的服务器,权为0,这样以虚拟点做单源最短路,就不需要求所有点的最短路。也就是构图的时候可以考虑为一类点构造一个虚拟的点,将问题化简。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值