ford-fulkerson 因未限定增广路径搜索方式,dfs 实现易因边方向错误、未清访问标记导致死循环或栈溢出;复杂度 o(e×max_flow),大流量下极慢;edmonds-karp 用 bfs 保证 o(v×e²) 复杂度,更稳定。

为什么 FordFulkerson 在 C++ 里容易跑不快甚至死循环
它本身不指定 BFS/DFS 实现方式,用 DFS 写错边方向或没清访问标记,就可能反复增广同一条路径;整数容量下虽能收敛,但复杂度是 O(E × max_flow),遇到大流量值(比如 1e9)直接卡死。
- 必须用残量图建模:对每条原边
u→v,建正向边cap[u][v]和反向边cap[v][u] = 0,增广后同步更新双向容量 - DFS 每次调用前要重置
visited[]数组,否则漏路径;BFS 更稳,推荐用queue+parent[]记录增广路 - 别用邻接矩阵存稀疏图——内存炸、遍历慢;改用邻接表 +
vector<pair long>> graph[N]</pair>存边和残量
EdmondsKarp 是什么,和裸 FordFulkerson 有什么区别
EdmondsKarp 就是把 FordFulkerson 的“找增广路”固定为 BFS,保证每次走最短路,复杂度降为 O(V × E²),可预测、不易崩。
- 核心差异在搜索方式:
FordFulkerson可以 DFS,EdmondsKarp必须 BFS;很多人口中的“FF 算法”实际指的就是EdmondsKarp - BFS 返回的是整条增广路径的瓶颈流量,不是单边容量;需沿路径回溯每条边取 min,再统一减去该值
- 反向边的残量要加回瓶颈值,这是反悔机制的关键——没这步,算法就退化成贪心,结果错误
用 DFS 实现 FordFulkerson 时怎么避免栈溢出和重复访问
递归 DFS 在深图(比如链状网络)上容易爆栈,且若不严格控制访问状态,会陷入 u→v→u 的死循环。
- 改用非递归 DFS:手动维护
stack<int></int>和当前路径上的最小残量,每次 pop 后检查是否到达汇点 - 访问标记不能只靠
visited[v],得结合当前路径上下文;更稳妥的是用parent[v] == -1判断未访问,同时记录入边索引防重边误判 - 对每个节点 v,遍历其邻接边时跳过残量为 0 的边,避免无效递归;C++ 中建议用
for (auto& [to, cap] : graph[u])配合引用避免拷贝
C++ 里处理大容量或浮点容量时要注意什么
标准 FordFulkerson 要求容量为非负整数,浮点数会导致精度误差累积,而超大整数(如 long long)则要小心溢出和比较逻辑。
立即学习“C++免费学习笔记(深入)”;
- 用
long long代替int存残量,但所有初始化、比较、减法都得保持类型一致;尤其注意if (cap > 0)别写成if (cap),防止隐式转换陷阱 - 浮点容量基本不推荐——IEEE 754 下
0.1 + 0.2 != 0.3,残量判断失效;真有需求,改用EPS = 1e-9做近似比较,但增广路径稳定性大幅下降 - 如果图含重边,邻接表插入时要合并同向边容量,否则残量更新错位;可用
map<pair>, long long></pair>预处理,但影响性能,优先在输入阶段合并
真正难的不是写通,而是残量图更新的时机和方向——多一条反向边没加、少一次 min 更新、某次 BFS 忘了清 parent 数组,结果就全错。这些地方没法靠编译器报错提醒,只能靠手动画两层残量变化来核对。










