【关系闭包】传递闭包 Warshall Floyd

(参考自:《离散数学》&  博客https://blog.csdn.net/ljhandlwt/article/details/52096932)

Warshall算法比较冷门,在这里不细说,贴个书上伪代码翻译过来的代码

 1     for(int i=0;i<maxn;++i) //
 2     for(int j=0;j<maxn;++j) //
 3     {
 4         if(Graph[i][j]){
 5             for(int k=0;k<maxn;++k){//在第i列中找
 6                 //遍历行
 7                 if(Graph[k][i])
 8                     Graph[k][j]=1;
 9             } 
10         }
11     }
View Code

主要谈谈Floyd算法,因为之前做题的时候在一个坑上栽了很久: 

  Floyd 的中转节点为最外层遍历!!

·遍历的次序 中转节点在最外层

 

For(k)   //中转节点

  For(i) 

    For(j)

      If()  { 松弛 ;}

每次的松弛操作 val[i][j] = max/min(val[i][j], val[i][k]+val[k][j]),如果是将k放在最内层,则i和j之间的松弛是一遍松弛完,则只有在ikkj间的权值都已经取到minmax,才能实现i和j之间取到最值,然而这在大多数情况下是不能满足的。

而将中间点k放在最外层,那么在i到j的点集中(不含ij,假设是顺序编号,之后可以推广到非顺序编号,即将ij之间能连通的店自己默认编号),假设编号最大为m,那么在外层循环k取到m时,val[i][j]必然取到了最小值(以最小值为例,最大值类似)

 

归纳法证明:

m1i到h中的最大编号,m2h到j中的最大编号--> i<m1<m2<j

假设结论成立,则k==m1 val[i][h]已经取到最小值,k==m2 val[h][j]已经取到最小值又因为m2ij中编号最大的,m2是最后一次遍历,则执行松弛操作

  val[i][j] = max/min(val[i][j], val[i][k]+val[k][j])

此时 ,由之前的推论val[i][k]和val[k][j]都已经取到最小值,那么对应的val[i][j]也取到其最小值

 

有时候,用Floyd来进行传递闭包的操作,同样要将节点的遍历放在最外边:

 若将k放在最里层,那么传递操作 val[i][j] |= val[i][k] & val[k][j] ij之间的传递只有一遍,那么则要保证i k之间k j之间已经达到最大连通时,ij传递操作后才能达到最大的连通,然而放在最内层大多数情况下不满足,只有放在最外层遍历才可以,证明与上边的类似,在这不赘述。

综上所述,Floyd的遍历,节点要放在最外层!!

 

 

 

转载于:https://www.cnblogs.com/GorgeousBankarian/p/10745641.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值