79 lines
1.9 KiB
C++
79 lines
1.9 KiB
C++
#include <iostream>
|
||
#include <vector>
|
||
using namespace std;
|
||
|
||
/*
|
||
* Floyd-Warshall 传递闭包(Transitive Closure)
|
||
* ----------------------------------------------
|
||
* 用途:求有向图中任意两点 i -> j 是否可达。
|
||
*
|
||
* 核心思想:
|
||
* 如果 i 能到达 k 且 k 能到达 j
|
||
* 则 i 也能到达 j
|
||
*
|
||
* reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j])
|
||
*
|
||
* 输入:
|
||
* n:节点数量(默认节点编号为 0~n-1)
|
||
* m:边数量
|
||
* 若干有向边 u -> v
|
||
*
|
||
* 结果:
|
||
* reach[i][j] = true 表示可达
|
||
*/
|
||
|
||
int main() {
|
||
int n, m;
|
||
cin >> n >> m;
|
||
|
||
// reach[i][j] 表示 i 是否能到 j
|
||
vector<vector<bool>> reach(n, vector<bool>(n, false));
|
||
|
||
// 自身可达
|
||
for (int i = 0; i < n; i++) {
|
||
reach[i][i] = true;
|
||
}
|
||
|
||
// 输入边
|
||
for (int i = 0; i < m; i++) {
|
||
int u, v;
|
||
cin >> u >> v;
|
||
reach[u][v] = true;
|
||
}
|
||
|
||
/*
|
||
* Floyd 传递闭包核心循环
|
||
* i -> k -> j 中的 k 作为中间点
|
||
*
|
||
* 需要确保三重循环的顺序为:
|
||
* for(k)
|
||
* for(i)
|
||
* for(j)
|
||
*
|
||
* 必须这么写,因为:
|
||
* - k 作为阶段性“允许使用的中间点”
|
||
* - 在第 k 轮,只能使用编号 ≤ k 的中间节点
|
||
*/
|
||
for (int k = 0; k < n; k++) {
|
||
for (int i = 0; i < n; i++) {
|
||
// 如果 i → k 不可达,则无须检查 j
|
||
if (!reach[i][k]) continue;
|
||
for (int j = 0; j < n; j++) {
|
||
// 如果 k → j 可达,则 i → j 也可达
|
||
if (reach[k][j]) {
|
||
reach[i][j] = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 输出可达矩阵(可选)
|
||
for (int i = 0; i < n; i++) {
|
||
for (int j = 0; j < n; j++) {
|
||
cout << reach[i][j] << (j + 1 == n ? '\n' : ' ');
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|