本文讲解Dinic算法的思路
关于残余网络和增广路等概念的说明
问题
当$F$较大时
思路
Dinic算法的核心是每次寻找最短的增广路
证明
下面证明
此时有结论
下面使用数学归纳法
那么沿该路径中任何一条边编号增加不超过1
类似于上面
综上
优化
首先
算法描述
下面的算法只是大致的描述
Dinic算法 ( 输入 ) 网络$G(V,E)$ 输出 : 最大流$max\_flow$ : 步骤0. [准备]建立数组$iter[V]$
定义$max\_flow\gets0$ , 用邻接表$G[V]$存储网络 , ; 步骤1. [建立分层图]bfs(s,0)
当bfs(u,n)时 , 若$n_u$已定义 , 返回 , 否则记$n_u=n$ ; 并对$G[u]$中的所有元素$v$进行bfs(v, n+1) , 清零$iter[]$数组 。 。 步骤2. [有增广路吗
]若$n_t$未定义 ? 退出算法 , 返回$max\_flow$ , 。 步骤3. [寻找增广路]在$G$上DFS
寻找从$s$到$t$的简单路径 , 要求该路径上每条边$e\langle u,v\rangle$可用权值$(w_e-f_e)$大于0 , 并且$n_v>n_u$ , 若找到 。 记该路径上的权值最小的边权值为$f$ , 否则$f\gets0$ , DFS(u)时按顺序遍历$G[u]$ 。 若$G[u][i]$不可用 , $iter[u]\gets iter[u]+1$ , 。 步骤4. [找到了
更新残余网络]如果$f>0$ , 置$max\_flow\gets max\_flow+f$ , 对路径上的每条边$e$ 。 置$f_e\gets f_e+f$ , 记其反向边为$e'$ 。 置$w_{e'}\gets w_{e'}+f$ , 返回步骤3 。 。 步骤5. [没有找到]如果$f=0$
返回步骤1 , 。
复杂度
由于每次dfs都至少使一条边满流
模板
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#define V 5005 //V为顶点最大个数<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>视数据范围而定
#define INF 0x7fffffffffffffff
using namespace std;
typedef long long ll;
struct edge{
ll to, w, rev;
};
vector<edge> G[V];
int num[V], iter[V];
int s, t;//源点和汇点<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>是全局变量
ll max_flow();
ll dfs(ll u, ll f);
void bfs();
void add_edge(ll from, ll to, ll w);
ll max_flow() {
ll f = 0, flow = 0;
while(true) {
memset(iter, 0, sizeof(iter));
bfs();
if(num[t] == -1) return flow;
while(f = dfs(s, INF)) {
flow += f;
}
}
}
ll dfs(ll u, ll f) {
if(u == t) return f;
ll flow;
for(int &i = iter[u]; i < G[u].size(); i++) {
edge &e = G[u][i];//注意是引用<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>需要直接修改原图
if(e.w > 0 && num[u] < num[e.to]) {
if(flow = dfs(e.to, (f > e.w ? e.w : f))) {
//min函数有些编译器不给过<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>所以用三目
e.w -= flow;
//直接修改容量而非同时记录f和w<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>只是为了方便
G[e.to][e.rev].w += flow;
return flow;
}
}
}
return 0;
}
void bfs() {
memset(num, -1, sizeof(num));
queue<int> que;
que.push(s);
num[s] = 0;
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = 0; i < G[u].size(); i++){
edge &e = G[u][i];
if(e.w > 0 && num[e.to] < 0) {
num[e.to] = num[u] + 1;
que.push(e.to);
}
}
}
}
void add_edge(ll from, ll to, ll w) {
G[from].push_back(edge{to, w, G[to].size()});
G[to].push_back(edge{from, 0, G[from].size() - 1});
}
如有发现模板的错误请联系我指正