B3611 传递闭包
传递闭包?这是个啥玩意?
通俗地讲,传递闭包就是一个邻接矩阵,表达图连通性的邻接矩阵。要注意的是,在传递闭包里面,如果一个点不在任何一个环中,就规定一个点和自身不连通。
怎么求传递闭包?根据定义,我们发现他需要枚举两个点间是否存在路径。怎么枚举路径?当然要枚举路径上的点。这就让我们自然而然的想到了 Floyd-Warshall 算法。
Floyd-Warshall 运用了动态规划的思想,用
其中
在本例中,状态就是连通性,转移过程如下:
- 如果
i,j 直接联通,则f_{i,j}=1 - 如果
i,j 不直接连通,但可以通过中转节点k 连通,则f_{i,j}=1 - 如果枚举了所有中转节点都不能使
i,j 联通,则f_{i,j}=0
又注意到状态是
于是转移方程即为
其中
这个方程需要预处理直接存在的边。由于这样的边也用
附上完整代码:
#include <bits/stdc++.h>
using namespace std;
inline int read() {
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
int x=0;
while(ch>='0'&&ch<='9') x=(x*10)+(ch^48),ch=getchar();
return x;
}
inline void write(int x) {
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void wr(int x) {
write(x);
putchar(' ');
}
bool mp[105][105];
int n;
void Floyd_Warshall() {
for(int k=1;k<=n;++k) //注意要先枚举 k,可以自己手玩几个图想一想为什么
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
mp[i][j]|=mp[i][k]&mp[k][j];
}
int main(void) {
n=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
mp[i][j]=read();
Floyd_Warshall();
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j)
wr(mp[i][j]);
putchar('\n');
}
return 0;
}