NewCodeTemplate
This commit is contained in:
78
模板/图/Floyd闭包传递.cpp
Normal file
78
模板/图/Floyd闭包传递.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user