5、floyd算法

 

一、课程目标

  1. 路径
  2. 多源最短路径
  3. floyd算法
  4. 松弛设计
  5. 模拟过程
  6. 应用要点

二、目标详解

1、路径

路径指图的一组顶点组成的序列,按照路径的方向,相邻顶点在图上是邻接的。

如果顶点和边都不重复出现,则称为简单路径(simple path)。

如果起点和终点相同且没有其它重复的顶点和边,则称为环(cycle)。

2、多源最短路径

给定一个图,求其中任意两个点之间的最短路径,

3、floyd算法

floyd-warshall算法,是解决任意两点间最短路径的一种经典算法,可以正确处理有向图或负权图的最短路径问题,同时也可以被用于计算有向图的传递闭包。算法的时间复杂度为O(N^3),空间复杂度为O(N^2)。

分析任意顶点x到y的最短距离d(x, y),初始分为两种情况:

  • x能邻接到y,d(x, y) = w(边权)
  • x不邻接y,d(x, y) = oo(无穷大)

现在假设有一个顶点k,已经计算出d(x, k)和d(k, y),也即发现了一条新路径x -> k -> y,比较d(x, k) + d(k, y) < d(x, y),如果不等式成立就表示新的路径比原路径短,此时就可以更新d(x, y) = d(x, k) + d(k, y),这种做法称之为’松弛’。

”松弛“过程就是对两点间路径求最短距离的过程,如果x到y的所有中间顶点都参加了”松弛”,则最后运算的d(x, y)就是最短路径。

依次类推,遍历图中所有的顶点k,将其它点按照以上x和y的分类,对d(x, y)进行松弛,最后就得到了任意两个顶点之间的最短路径。

4、松弛设计

用一个n*n的矩阵d[N][N]存储任意两点之间的最短距离。

初始化:

  • d[i][i] = 0
  • d[i][j] = w(权),如果i邻接j
  • d[i][j] = oo(无穷大),如果i不邻接j

循环每个顶点k,对每个经过k的路径“松弛”:

  • 理解:d(x, k)即为矩阵第k列的每个元素, d(k, y)即为矩阵第k行的每个元素,
  • 因此,循环第k列的每个元素d[i][k],循环第k行的每个元素d[k][j],两两相加对原最短路径进行松弛。
      if(d[i][k] + d[k][j] < d[i][j])
        d[i][j] = d[i][k] + d[k][j];
    

每个顶点都这样松弛过之后,矩阵的每个元素即为任意两点间的最短距离。

代码模板

for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(nt j=1; j<=n; j++) {
    if(d[i][k] + d[k][j] < d[i][j])
      d[i][j] = d[i][k] + d[k][j];
}

5、模拟过程

最短路矩阵初始如下:

02oooo2
oo044oo
oooo06oo
oooooo08
oo10oooo0

对顶点1,循环第一列的所有值 + 循环第一行的所有值,进行松弛判断:

    if(d[i][k] + d[k][j] < d[i][j])
      d[i][j] = d[i][k] + d[k][j];

顶点1松弛结束,矩阵没有变化,因为顶点1没有进来的路径。

然后用顶点2进行松弛,红色的是被松弛的点:

02662
oo044oo
oooo06oo
oooooo08
oo1014140

与原始矩阵对照,可以看出松弛的过程:

  • 例如:d[1][3]原来不通,现在经过2中转,d[1][2] + d[2][3]=6<oo,于是d[1][3]->6

提示:有一个技巧叫十字交叉法,顶点2对应第二行、第二列,其它元素的值与横纵对应元素的和进行比较。

依次松弛下去,最后得到:

02662
oo04412
oo240614
oo182208
oo1014140

6、应用要点

回路

一般Floyd都应用与有向图,但也可用于无向图,但两者有一些区别。

核心在于回路,如果存在负回路,也即可以无限制走下去,每次路径都小于原路径,此时Floyd算法就会失真。

有向图的回路情况不多,而无向图肯定是回路,因此无向图基本要都是正边才好用此算法。

最大路

如果求最大路径,可把权设置为负的求最短路,最后再正回来。

路径

如果要输出路径,可用path[i][j]来表示i->j最短路上j的前趋点,最后反向输出。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值