最大流dinic算法,模板题
EK算法,每次调用一次 bfs,只能找到一条 增光路。
dinic算法每调用一次 bfs, 就可以找到多条的增光路。
本题要点:
1、dinic 步骤
a) 用bfs建立分层图, 实际是一个增广网
b) 建立一个分层图后,再 dfs 在增广网,计算所有可能的增广路上的流量的总和.
2、dinic 算法的剪枝:当前弧优化:
now 数组,记录每个点将要访问的第一条边。
在bfs建立分层图的时候,某个点 x 第一次入队列, now[x] = head[x]。
在 dfs 的过程中,一次处理的多条增光路,这些增光路可能在某个点相交(假设为x点),
就会多次调用函数 dfs(x, long long sum), 每次从 now[x]中,选择第一条要处理的边。
假设 x点有 y, z, w 三条边, x点的上一点是 fax。第一次进入 dfs(x, sum), 处理了 y 边,剩下 z 和 w 边。
但是此时 边 fax --> x 的流量不足,所以无法处理 z和 w边。 这时候,在for循环内,now[x] = i; //当前弧优化,
也就是把x点的将要处理的第一条边设为 了y边。
for(int i = now[x]; i && sum; i = e[i].next)
{
now[x] = i; //当前弧优化
...
}
第二次进入点x,调用函数 dfs(x, sum), 此时的now[x] 指向了y边。
3、dinic 算法的剪枝:去掉增广完毕的点
k = dfs(v, min(sum, e[i].val));
if(k == 0)
dis[v] = inf; //剪枝,去掉增广完毕的点
k = dfs(v, min(sum, e[i].val)); k是表示当前走点v,能流过的最大流量是k, 当k == 0, 说明此点走不通,
直接赋值 dis[v] = inf, 后面就不会进入点v,因为不满足分层图的 (u点到v点有 边) d[u] + 1 == d[v] 的要求。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int MaxN = 520010;
const long long inf = 2005020600;
int n, m, s, t, u, v;
long long w, ans, dis[MaxN];
int tot = 1, now[MaxN], head[MaxN];
struct node
{
int to, next;
long long val;
}e