D111【模板】最短路→传递闭包 Floyd 算法 B3611 传递闭包

D111【模板】最短路→传递闭包 Floyd 算法 B3611 传递闭包_哔哩哔哩_bilibili

 

Floyd 算法可以处理 最短路、最小环、传递闭包等问题

传递闭包:给定一个集合,以及若干元素的传递关系,求解所有元素的传递关系

如给定集合 {a,b,c},已知 a>b , b>c ,可以推出 a>c

在图论中,传递闭包用于计算有向图的可达性关系

B3611 【模板】传递闭包 - 洛谷

给定一张点数为 n 的有向图的邻接矩阵,求该有向图的传递闭包。

思路

$d[i][j]=1/0$ 表示 $i$ 可达/不可达 $j$

用 Floyd 算法处理可达性,只有 $d[i][k]$ 与 $d[k][j]$ 均为 1 时,$d[i][j]$ 才为 1,改成与、或运算

image   image

以上两种写法是等价的,其实代码的第三层循环可以用 bitset 优化掉

若 $d[k]$ 的 $j$ 位是 1,则让 $d[i]$ 的 $j$ 位是 1;若 $d[k]$ 的 $j$ 位是 0,则 $d[i]$ 的 $j$ 位保持原值

所以第三层循环可以等价替换为 $d[i]=d[i]|d[k]$

image   

时间复杂度从 $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';
  }
}

 

posted @ 2026-03-21 14:26  董晓  阅读(38)  评论(0)    收藏  举报