附上学习路径
https://www.luogu.org/blog/ONE-PIECE/wang-lao-liu-jiang-xie-zhi-dinic
https://www.cnblogs.com/y-clever/p/6308820.html
洛谷真是个神奇的地方:(太强了)
https://www.luogu.org/problemnew/solution/P4722
yh大佬的板子:
https://blog.csdn.net/henuyh/article/details/80637636
FF模板
const int inf = 0x7fffffff;
const int maxn = 205;
struct node
{
int v, w, nex;
}edge[maxn * maxn];
int cnt, s, t;
int m, n;
int head[maxn], pre[maxn], rec[maxn], flow[maxn];
stack<int> stk;
void init()
{
cnt = 0;
memset(head, -1, sizeof head);
}
void addedge(int u, int v, int w){
//正向建边
edge[cnt] = {v, w, head[u]};
head[u] = cnt++;
//反向建边
edge[cnt] = {u, 0, head[v]};
head[v] = cnt++;
}
int dfs(int S, int T)
{
memset(pre, -1, sizeof pre);
while(!stk.empty()) stk.pop();
pre[S] = S; flow[S] = inf;
stk.push(S);
while(!stk.empty()) //用栈迭代替代dfs深搜
{
int top = stk.top();
stk.pop();
int k = head[top];
while(k != -1)
{
if(pre[edge[k].v] == -1 && edge[k].w > 0)
{
flow[edge[k].v] = min(flow[top], edge[k].w);
pre[edge[k].v] = top; //连v的点
rec[edge[k].v] = k; //连v的这条边
stk.push(edge[k].v);
}
k = edge[k].nex;
}
if(pre[T] != -1) return flow[T];
}
return -1;
}
int FF(int s, int t)
{
int ans = 0, add;
while((add = dfs(s, t)) != -1) //直到找不到增广路
{
ans += add;
int k = t;
while(k != s)
{
edge[rec[k]].w -= add;
edge[rec[k]^1].w += add;
k = pre[k];
}
}
return ans;
}
EK 模板
// 链式向前星
int cnt;
struct ac{
int v, c, nex;
}edge[maxm];
bool vis[maxn];
int head[maxn], path[maxn];
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int c){
//正向建边
edge[cnt] = {v, c, head[u]};
head[u] = cnt++;
//反向建边
edge[cnt] = {u, 0, head[v]};
head[v] = cnt++;
}
bool bfs(int s, int t){ // 找最短的增广路
memset(vis, 0, sizeof(vis));
memset(path, -1, sizeof(path));
queue<int> que;
que.push(s);
vis[s] = 1;
while (!que.empty()) {
int u = que.front();
que.pop();
// 遍历u 的所有的出边
for (int i = head[u]; i != -1; i = edge[i].nex) {
int v = edge[i].v;
int c = edge[i].c;
// 判断能否增广
if(vis[v] || c == 0) continue;
path[v] = i;
vis[v] = 1;
que.push(v);
if(v == t) return true; //分层成功,找到增广路
}
}
return false;
}
int EK (int s, int t) {
int ans = 0;
while( bfs(s, t) ) { // 找到增广路
int flow = inf;
for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
flow = min(flow, edge[i].c);
}
for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
edge[i].c -= flow;
edge[i^1].c += flow;
}
ans += flow;
}
return ans;
}
// 临接矩阵
// pre记录前驱节点
int G[maxn][maxn], pre[maxn], vis[maxn], n, m;
// BFS找增广路
bool bfs(int s, int e) {
memset(vis, 0, sizeof(vis));
memset(pre, -1, sizeof(pre));
pre[s] = s;
vis[s] = 1;
queue<int> que;
que.push(s);
while (!que.empty()) {
int u = que.front();
que.pop();
// 访问u所有的出边, 判断能否增广
for (int i = 0; i <= e; i++) {
if (G[u][i] && !vis[i]) {
pre[i] = u;
que.push(i);
vis[i] = 1;
if (i == e) return 1; // 到汇点存在增广路
}
}
}
return 0;
}
int EK(int s, int e) {
int ans = 0;
while (bfs(s, e)) { // 判断是否存在增广路
int MIN = inf;
// 遍历增广路上所有边取流量最小的边
for (int i = e; i != s; i = pre[i]) {
MIN = min(MIN, G[pre[i]][i]);
}
// 更新增广路上的流量, 正向减,反向加
for (int i = e; i != s; i = pre[i]) {
G[pre[i]][i] -= MIN;
G[i][pre[i]] += MIN;
}
ans += MIN;
}
return ans;
}
Dinic
const int maxn = 1010;
const int maxm = 4e5 + 10;
const int inf = 0x3f3f3f3f;
int s, t;
struct ac{
int v, c, nex;
}edge[maxm];
int head[maxn], dis[maxn], curedge[maxn], cnt;
void init () {
cnt = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int c){
//正向建边
edge[cnt] = {v, c, head[u]};
head[u] = cnt++;
//反向建边
edge[cnt] = {u, 0, head[v]};
head[v] = cnt++;
}
bool bfs(){ //对图分层
memset(dis, 0, sizeof(dis));
queue<int> que;
que.push(s);
dis[s] = 1;
while(!que.empty()) {
int u = que.front();
que.pop();
// 遍历u的所有出边
for (int i = head[u]; i != -1; i = edge[i].nex) {
int v = edge[i].v;
int c = edge[i].c;
// 如果节点v未分过层或者 u->v流量不为0
if( dis[v] || c == 0) continue;
dis[v] = dis[u] + 1; //v 为 u的下一层 压入队列
que.push(v);
//if (v == e)
//break;
}
}
return dis[t] > 0; // 判断是否存在增广路,s是否能到达e
}
int dfs(int u, int flow){
if (u == t || flow == 0) return flow;
//遍历u的所有的出边
for (int i = curedge[u]; i != -1; i = edge[i].nex) {
int v = edge[i].v;
int c = edge[i].c;
// 判断 u -> v 能否增广
if (dis[v] != dis[u] + 1 || c == 0) continue;
int d = dfs(v, min(flow, c));
if (d > 0) { //找到增广路,修改增广路上的正反向边的流量
edge[i].c -= d;
edge[i ^ 1].c += d;
curedge[u] = i; //当前弧优化
return d;
}
}
dis[u] = -1; // 炸点优化
return 0;
}
/*
int dfs(int u, int flow){
if (u == t) return flow;
//遍历u的所有的出边
int totflow = 0; //当前点的流量
for (int i = curedge[u]; i != -1; i = edge[i].nex) {
int v = edge[i].v;
int c = edge[i].c;
// 判断 u -> v 能否增广
if (dis[v] != dis[u] + 1 || c == 0) continue;
int d = dfs(v, min(flow - totflow, c));
if (d > 0) { //找到增广路,修改增广路上的正反向边的流量
edge[i].c -= d;
edge[i ^ 1].c += d;
totflow += d;
curedge[u] = i; //当前弧优化
if(flow == totflow) return totflow;
}
}
if(!totflow)
dis[u] = -1; // 炸点优化
return totflow;
}
int Dinic(){
int Sum = 0, d;
while (bfs()) {// 分层
// copy head数组,在dfs中可以直接得到下一条没有被增广过的边
for(int i = 0; i <= ; ++i) curedge[i] = head[i];
//多次找增广路
Sum += dfs(s, inf);
}
return Sum;
}
*/
int Dinic(){
int Sum = 0, d;
while (bfs()) {// 分层
// copy head数组,在dfs中可以直接得到下一条没有被增广过的边
for(int i = 0; i <= ; ++i) curedge[i] = head[i];
//多次找增广路
while((d = dfs(s, inf)) > 0) {
Sum += d;
}
}
return Sum;
}