D111【模板】最短路→传递闭包 Floyd 算法 B3611 传递闭包
D111【模板】最短路→传递闭包 Floyd 算法 B3611 传递闭包_哔哩哔哩_bilibili
Floyd 算法可以处理 最短路、最小环、传递闭包等问题
传递闭包:给定一个集合,以及若干元素的传递关系,求解所有元素的传递关系
如给定集合 {a,b,c},已知 a>b , b>c ,可以推出 a>c
在图论中,传递闭包用于计算有向图的可达性关系
给定一张点数为 n 的有向图的邻接矩阵,求该有向图的传递闭包。

思路
$d[i][j]=1/0$ 表示 $i$ 可达/不可达 $j$
用 Floyd 算法处理可达性,只有 $d[i][k]$ 与 $d[k][j]$ 均为 1 时,$d[i][j]$ 才为 1,改成与、或运算

以上两种写法是等价的,其实代码的第三层循环可以用 bitset 优化掉
若 $d[k]$ 的 $j$ 位是 1,则让 $d[i]$ 的 $j$ 位是 1;若 $d[k]$ 的 $j$ 位是 0,则 $d[i]$ 的 $j$ 位保持原值
所以第三层循环可以等价替换为 $d[i]=d[i]|d[k]$

时间复杂度从 $O(n^3)$ 降为 $O(n^2*\frac n {w 字长})$
// 最短路→传递闭包 Floyd 算法 O(n^3) #include<bits/stdc++.h> using namespace std; int n,d[110][110]; int main(){ cin>>n; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) cin>>d[i][j]; for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) d[i][j]|=d[i][k]&d[k][j]; for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++)cout<<d[i][j]<<' '; cout<<'\n'; } }
// 传递闭包 Floyd 算法 O(n^3) #include<bits/stdc++.h> using namespace std; int n,d[110][110]; int main(){ cin>>n; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) cin>>d[i][j]; for(int k=1; k<=n; k++) for(int i=1; i<=n; i++)if(d[i][k]) for(int j=1; j<=n; j++) if(d[k][j]) d[i][j]=1;
for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++)cout<<d[i][j]<<' '; cout<<'\n'; } }
// 传递闭包 Floyd+bitset O(n^2) #include<bits/stdc++.h> using namespace std; int n,x; bitset<110> d[110]; int main(){ cin>>n; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) cin>>x, d[i][j]=x; for(int k=1; k<=n; k++) for(int i=1; i<=n; i++)if(d[i][k]) d[i]|=d[k]; for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++)cout<<d[i][j]<<' '; cout<<'\n'; } }
浙公网安备 33010602011771号