#include #include 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> reach(n, vector(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; }