Dinic算法
Dinic 何尝又不是EK的一种变形呢?
以下是Dinic算法的C++实现,包含详细的代码注释,帮助理解算法的每个步骤。
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;
struct Edge {
int to; // 边的终点
int rev; // 反向边在邻接表中的位置
int flow; // 当前流量
int cap; // 容量
};
class Dinic {
private:
int n; // 节点数量
vector<vector<Edge>> graph; // 邻接表表示的图
vector<int> level; // 节点的层级(用于BFS分层)
vector<int> ptr; // 当前弧优化指针(用于DFS)
// BFS分层:构建层次图,返回是否能到达汇点
bool bfs(int s, int t) {
fill(level.begin(), level.end(), -1);
queue<int> q;
level[s] = 0; // 源点层级为0
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
// 遍历所有邻边
for (Edge &e : graph[u]) {
// 如果该边还有剩余容量,并且目标节点未被分层
if (e.flow < e.cap && level[e.to] == -1) {
level[e.to] = level[u] + 1; // 层级+1
q.push(e.to);
}
}
}
return level[t] != -1; // 返回是否能到达汇点
}
// DFS寻找阻塞流(多路增广)
int dfs(int u, int t, int flow) {
if (u == t || flow == 0) {
return flow; // 到达汇点或没有剩余流量
}
// 使用当前弧优化,避免重复检查已经处理过的边
for (int &i = ptr[u]; i < graph[u].size(); i++) {
Edge &e = graph[u][i];
// 只向更高层级的节点推进
if (level[e.to] == level[u] + 1) {
// 递归寻找增广路径
int pushed = dfs(e.to, t, min(flow, e.cap - e.flow));
if (pushed > 0) {
// 更新边的流量
e.flow += pushed;
// 更新反向边的流量
graph[e.to][e.rev].flow -= pushed;
return pushed;
}
}
}
return 0; // 没有找到增广路径
}
public:
Dinic(int n) : n(n) {
graph.resize(n);
level.resize(n);
ptr.resize(n);
}
// 添加有向边(同时自动添加反向边)
void addEdge(int from, int to, int cap) {
// 正向边
graph[from].push_back({to, (int)graph[to].size(), 0, cap});
// 反向边(初始容量为0)
graph[to].push_back({from, (int)graph[from].size() - 1, 0, 0});
}
// 计算最大流
int maxFlow(int s, int t) {
int total_flow = 0;
// 只要还能分层(即还能找到增广路径)
while (bfs(s, t)) {
fill(ptr.begin(), ptr.end(), 0); // 重置当前弧指针
// 不断寻找阻塞流
while (int pushed = dfs(s, t, INT_MAX)) {
total_flow += pushed;
}
}
return total_flow;
}
};
int main() {
// 示例:解决一个简单的网络流问题
Dinic dinic(6); // 创建6个节点的图
// 添加边(起点,终点,容量)
dinic.addEdge(0, 1, 10);
dinic.addEdge(0, 2, 10);
dinic.addEdge(1, 2, 2);
dinic.addEdge(1, 3, 4);
dinic.addEdge(1, 4, 8);
dinic.addEdge(2, 4, 9);
dinic.addEdge(3, 5, 10);
dinic.addEdge(4, 3, 6);
dinic.addEdge(4, 5, 10);
// 计算从节点0(源点)到节点5(汇点)的最大流
cout << "Maximum flow: " << dinic.maxFlow(0, 5) << endl;
return 0;
}
关键部分详细解释
1. 数据结构
Edge结构体存储边的信息:to: 边的终点rev: 反向边在邻接表中的位置(用于快速查找)flow: 当前流量cap: 边的容量
2. BFS分层 (bfs函数)
- 为每个节点分配层级,形成分层图
- 只考虑有剩余容量的边(
e.flow < e.cap) - 返回是否能到达汇点(判断算法是否继续)
3. DFS寻找阻塞流 (dfs函数)
- 使用当前弧优化(
ptr数组)避免重复检查边 - 只向更高层级的节点推进(
level[e.to] == level[u] + 1) - 递归寻找增广路径并更新流量
4. 最大流计算 (maxFlow函数)
- 不断执行BFS分层和DFS阻塞流寻找
- 直到无法再分层(没有增广路径)为止
5. 当前弧优化
ptr数组记录每个节点已经检查过的边- 避免在多次DFS中重复检查不可能再增广的边
复杂度分析
- 时间复杂度:O(V²E)
- 空间复杂度:O(V+E)
这个实现包含了Dinic算法的所有关键优化,包括分层图、阻塞流和当前弧优化,是解决网络流问题的高效实现。

浙公网安备 33010602011771号