# 网络流:模板

# P3376 网络最大流(Dinic)

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
const int N = 11000, M = 110000;
const int INF = 0x7fffffff;
struct node {
	int u, v, w, next;
} e[M << 1];
int cur[N], h[N], tot;
int dfn[N], ans, n, m, s, t;
void add(int u, int v, int w) {
	e[tot] = node({u, v, w, h[u]});
	cur[u] = h[u] = tot++;
}
bool bfs() {
	memset(dfn, 0, sizeof dfn);
	queue<int> q;
	dfn[s] = 1;
	q.push(s);
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		for(int i = h[u]; i != -1; i = e[i].next) {
			int v = e[i].v;
			if(e[i].w and !dfn[v]) {
				dfn[v] = dfn[u] + 1;
				q.push(v);
				if(v == t) return true;
			}
		}
	}
	return false;
}
int dfs(int u, int low) {
	if(u == t) return low;
	int w = low;
	for(int i = cur[u]; i != -1; i = e[i].next) {
		int v = e[i].v;
		cur[u] = i;
		if(e[i].w and dfn[v] == dfn[u] + 1) {
			int f = dfs(v, min(w, e[i].w));
			e[i].w -= f; e[i^1].w += f;
			w -= f;
			if(!w) break;
		}
	}
	return low - w;
}
void dinic() {
	while(bfs()) {
		memcpy(cur, h, sizeof cur);
		ans += dfs(s, INF);
	}
}
int main() {
	scanf("%d%d%d%d", &n, &m, &s, &t);
	memset(h, -1, sizeof h);
	for(int i=1, u, v, w; i<=m; ++i) {
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w);
		add(v, u, 0);
	}
	dinic();
	printf("%d\n", ans);
	return 0;
}

# P3381 最小费用最大流(单路增广)

# Dijkstra

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define il inline
const int N = 5500, M = 55000, INF = 0x3f3f3f3f;
struct point {
    int u, val;
    point(int _u = 0, int _val = 0): u(_u), val(_val) {}
    bool operator < (const point &o) const { return val > o.val; } 
};
priority_queue <point> q;
struct node {
    int u, v, w, f, next;
    node() {}
} e[M << 1];
int head[N], tot = 0;
il void add(int u, int v, int w, int f) {
    e[tot].u = u, e[tot].v = v, e[tot].w = w, e[tot].f = f;
    e[tot].next = head[u]; head[u] = tot++;
}
int h[N], dis[N], flow[N], pre[N];
int n, m, s, t;
int maxflow = 0, mincost = 0;
il bool dijkstra() {
    memset(dis, 0x3f, sizeof dis);
    memset(flow, 0x3f, sizeof flow);
    memset(pre, -1, sizeof pre);
    
    dis[s] = 0;
    q.push(point(s, 0));
    while (!q.empty()) {
        int u = q.top().u, val = q.top().val;
        q.pop();
        if (val > dis[u]) continue;
        for (int i = head[u]; i != -1; i = e[i].next) {
            int v = e[i].v;
            if (e[i].w and dis[v] > dis[u] + e[i].f + h[u] - h[v]) {
                pre[v] = i;
                flow[v] = min(flow[u], e[i].w);
                dis[v] = dis[u] + e[i].f + h[u] - h[v];
                q.push(point(v, dis[v]));
            }
        }
    }
    return dis[t] != INF;
}
il void check() {
    
    for (int p = pre[t]; p != -1; p = pre[e[p].u]) {
        e[p].w -= flow[t];
        e[p^1].w += flow[t];
    }
    maxflow += flow[t];
    mincost += (dis[t] - h[s] + h[t]) * flow[t];
    
    for(int i=1; i<=n; ++i) h[i] += dis[i];
}
int main() {
    
    memset(head, -1, sizeof head);
    
    scanf("%d%d%d%d", &n, &m, &s, &t);
    for(int i=1, u, v, w, f; i<=m; ++i) {
        scanf("%d%d%d%d", &u, &v, &w, &f);
        add(u, v, w, f);
        add(v, u, 0, -f);
    }
    
    while (dijkstra()) check();
    printf("%d %d\n", maxflow, mincost);
    
    return 0;
}

# SPFA

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
const int N = 5500, M = 110000, INF = 0x3f3f3f3f;
struct node {
    int u, v, w, f, next;
} e[M];
int h[N], tot = 0;
void add(int u, int v, int w, int f) {
    e[tot] = {u, v, w, f, h[u]};
    h[u] = tot++;
}
int pre[N], flow[N], dis[N];
bool vis[N];
int n, m, s, t, maxflow, mincost;
bool spfa() {
    
    memset(pre, -1, sizeof pre);
    memset(vis, false, sizeof vis);
    memset(dis, 0x3f, sizeof dis);
    memset(flow, 0x3f, sizeof flow);
    
    queue<int> q;
    q.push(s);
    vis[s] = true;
    dis[s] = 0;
    
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = h[u]; i != -1; i = e[i].next) {
            int v = e[i].v;
            if(e[i].w and dis[v] > dis[u] + e[i].f) {
                dis[v] = dis[u] + e[i].f;
                pre[v] = i;
                flow[v] = min(flow[u], e[i].w);
                if(!vis[v]) {
                    q.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    
    return dis[t] != INF;
}
void check() {
    for(int p = pre[t]; p != -1; p = pre[e[p].u]) {
        e[p].w -= flow[t];
        e[p^1].w += flow[t];
    }
    
    mincost += dis[t] * flow[t];
    maxflow += flow[t];
}
int main() {
    
    scanf("%d%d%d%d", &n, &m, &s, &t);
    
    memset(h, -1, sizeof h); 
    for(int i=1, u, v, w, f; i<=m; ++i) {
        scanf("%d%d%d%d", &u, &v, &w, &f);
        add(u, v, w, f);
        add(v, u, 0, -f);
    }
    
    while(spfa()) check();
    
    printf("%d %d\n", maxflow, mincost);
    return 0;
}

# LOJ115 无源汇有上下界可行流(超级源汇)

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define il inline
const int N = 220, M = 11000, INF = 0x3f3f3f3f;
struct node {
    int u, v, w, next;
} e[M * 6];
int head[N], cur[N], tot = 0;
il void add(int u, int v, int w) {
    e[tot] = (node) {u, v, w, head[u]};
    head[u] = tot++;
}
int h[N], n, m, ss, tt;
il bool bfs() { // 分层 
    
    memset(h, 0, sizeof h);
    memcpy(cur, head, sizeof cur);
    queue<int> q;
    q.push(ss);
    h[ss] = 1;
    
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; i != -1; i = e[i].next) {
            int v = e[i].v;
            if(e[i].w and !h[v]) {
                h[v] = h[u] + 1;
                if(v == tt) return true;
                q.push(v);
            }
        }
    }
    return false;
}
int dfs(int u, int low) {
    if(u == tt) return low;
    int w = low;
    for(int i = cur[u]; i != -1; i = e[i].next, cur[u] = i) {
        int v = e[i].v;
        if(e[i].w and h[v] == h[u] + 1) {
            int f = dfs(v, min(w, e[i].w));
            e[i].w -= f;
            e[i^1].w += f;
            w -= f;
            if(!w) break;
        }
    }
    return low - w;
}
int tflow = 0, sflow = 0;
il void dinic() {
    
    for(int i = head[ss]; i != -1; i = e[i].next)
        sflow += e[i].w; // 出流量 
        
    while(bfs()) dfs(ss, INF);
    
    for(int i = head[tt]; i != -1; i = e[i].next) 
        tflow += e[i].w; // 入流量 
    
    if(sflow == tflow) { // 满流 
        printf("YES\n");
        for(int i=0; i<tot; i+=6) 
            printf("%d\n", e[i+1].w + e[i+5].w); // 反边流量和 
    } else printf("NO\n");
    
}
int main() {
    
    freopen("loj115.in", "r", stdin);
    
    scanf("%d%d", &n, &m);
    
    memset(head, -1, sizeof head);
    ss = 0, tt = n+1;
    for(int i=1, u, v, l, h; i<=m; ++i) { // 建图 
        scanf("%d%d%d%d", &u, &v, &l, &h);
        add(u, tt, l);
        add(tt, u, 0);
        add(ss, v, l);
        add(v, ss, 0);
        add(u, v, h-l);
        add(v, u, 0);
    }
    
    dinic();
    
    return 0;
}

# 有源汇有上下界(转无源汇,然后断边)

# 最大流(顺流增广)

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
const int N = 220, M = 22000, INF = 0x3f3f3f3f;
struct node {
	int u, v, w, next;
} e[M];
int head[N], cur[N], tot = 0;
void add(int u, int v, int w) {
	e[tot] = (node) {u, v, w, head[u]};
	head[u] = tot++;
	e[tot] = (node) {v, u, 0, head[v]};
	head[v] = tot++;
}
int h[N], in[N], n, m, s, t, ss, tt, sflow = 0, tflow = 0;
bool bfs(int s, int t) {
	
	memset(h, 0, sizeof h);
	memcpy(cur, head, sizeof cur);
	
	queue<int> q;
	q.push(s);
	h[s] = 1;
	
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		for(int i = head[u], v; i != -1; i = e[i].next) {
			v = e[i].v;
			if(e[i].w and !h[v]) {
				h[v] = h[u] + 1;
				if(v == t) return true;
				q.push(v); 
			}
		}
	}
	return false;
}
int dfs(int u, int low, int t) {
	if(u == t) return low;
	
	int w = low;
	for(int i = cur[u], v; i != -1; i = e[i].next, cur[u] = i) {
		v = e[i].v;
		if(e[i].w and h[v] == h[u] + 1) {
			int f = dfs(v, min(w, e[i].w), t);
			e[i].w -= f;
			e[i^1].w += f;
			w -= f;
			if(!w) break;
		}
	}
	return low - w;
}
int main() {
	
	//freopen("loj116.in", "r", stdin);
	
	scanf("%d%d%d%d", &n, &m, &s, &t);
	
	ss = 0, tt = n+1;
	memset(head, -1, sizeof head);
	for(int i=1, u, v, l, h; i<=m; ++i) {
		scanf("%d%d%d%d", &u, &v, &l, &h);
		in[u] -= l; in[v] += l;
		add(u, v, h-l);
	}
	
	for(int i=1; i<=n; ++i) {
		if(!in[i]);
		else if(in[i] > 0) {
			sflow += in[i];
			add(ss, i, in[i]);
		} else {
			add(i, tt, -in[i]);
		}
	}
	
	add(t, s, INF);
	
	while(bfs(ss, tt)) tflow += dfs(ss, INF, tt);
	
	if(sflow != tflow) {
		printf("please go home to sleep\n");
		return 0;
	}
	
	for(int i = head[ss]; i != -1; i = e[i].next) 
		e[i].w = e[i^1].w = 0;
	
	for(int i = head[tt]; i != -1; i = e[i].next)
		e[i].w = e[i^1].w = 0;
	
	int sum = e[--tot].w;
	e[tot-1].w = e[tot].w = 0;
	
	while(bfs(s, t)) sum += dfs(s, INF, t);
	
	printf("%d\n", sum);
		
	return 0;
}

# 最小流(逆流增广)

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
using namespace std;
const int N = 220, M = 22000, INF = 0x3f3f3f3f;
struct node {
	int u, v, w, next;
} e[M];
int head[N], cur[N], tot = 0;
void add(int u, int v, int w) {
	e[tot] = (node) {u, v, w, head[u]};
	head[u] = tot++;
	e[tot] = (node) {v, u, 0, head[v]};
	head[v] = tot++;
}
int h[N], in[N], n, m, s, t, ss, tt, sflow = 0, tflow = 0;
bool bfs(int s, int t) {
	
	memset(h, 0, sizeof h);
	memcpy(cur, head, sizeof cur);
	
	queue<int> q;
	q.push(s);
	h[s] = 1;
	
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		for(int i = head[u], v; i != -1; i = e[i].next) {
			v = e[i].v;
			if(e[i].w and !h[v]) {
				h[v] = h[u] + 1;
				if(v == t) return true;
				q.push(v); 
			}
		}
	}
	return false;
}
int dfs(int u, int low, int t) {
	if(u == t) return low;
	
	int w = low;
	for(int i = cur[u], v; i != -1; i = e[i].next, cur[u] = i) {
		v = e[i].v;
		if(e[i].w and h[v] == h[u] + 1) {
			int f = dfs(v, min(w, e[i].w), t);
			e[i].w -= f;
			e[i^1].w += f;
			w -= f;
			if(!w) break;
		}
	}
	return low - w;
}
int main() {
	
	//freopen("loj116.in", "r", stdin);
	
	scanf("%d%d%d%d", &n, &m, &s, &t);
	
	ss = 0, tt = n+1;
	memset(head, -1, sizeof head);
	for(int i=1, u, v, l, h; i<=m; ++i) {
		scanf("%d%d%d%d", &u, &v, &l, &h);
		in[u] -= l; in[v] += l;
		add(u, v, h-l);
	}
	
	for(int i=1; i<=n; ++i) {
		if(!in[i]);
		else if(in[i] > 0) {
			sflow += in[i];
			add(ss, i, in[i]);
		} else {
			add(i, tt, -in[i]);
		}
	}
	
	add(t, s, INF);
	
	while(bfs(ss, tt)) tflow += dfs(ss, INF, tt);
	
	if(sflow != tflow) {
		printf("please go home to sleep\n");
		return 0;
	}
	
	for(int i = head[ss]; i != -1; i = e[i].next) 
		e[i].w = e[i^1].w = 0;
	
	for(int i = head[tt]; i != -1; i = e[i].next)
		e[i].w = e[i^1].w = 0;
	
	int sum = e[--tot].w;
	e[tot-1].w = e[tot].w = 0;
	
	while(bfs(s, t)) sum += dfs(s, INF, t);
	
	printf("%d\n", sum);
		
	return 0;
}