const int maxn = 10000 + 10, maxm = 200000 + 10; const int inf = 0x3f3f3f3f; int n, m, S, T; int head[maxn], edges[maxm], ver[maxm], ne[maxm], tot = 1;
void add(int a, int b, int c) { ver[++tot] = b; edges[tot] = c; ne[tot] = head[a]; head[a] = tot; }
while (q.size()) { int x = q.front(); q.pop(); for (int i = head[x]; i; i = ne[i]) { int y = ver[i]; if (d[y] == -1 && edges[i]) { cur[y] = head[y]; d[y] = d[x] + 1; if (y == T) returntrue; q.push(y); } } } returnfalse; }
int dfs(int u, int limit) { if (u == T) returnlimit; int flow = 0; for (int i = cur[u]; i && limit > flow; i = ne[i]) { cur[u] = i; int v = ver[i]; if (d[v] == d[u] + 1 && edges[i]) { int t = dfs(v, min(edges[i], limit-flow)); if (!t) d[v] = -1; edges[i] -= t, edges[i^1] += t, flow += t; } } return flow; }
int dinic() { int res = 0, flow; while (bfs()) { while (true) { flow = dfs(S, inf); if (flow == 0) break; res += flow; } } return res; }
int main() { freopen("input.txt", "r", stdin); scanf("%d%d%d%d", &n, &m, &S, &T); while (m--) { int u, v, c; scanf("%d%d%d", &u, &v, &c); add(u, v, c); add(v, u, 0); }
// dinic int ans = dinic(); printf("%d\n", ans); }
给定一个无向图 G=(V,E),一个匹配是边的一个子集 M⊆E
使得对于所有节点∀v∈V,子集 M 中最多有一条边与 v 相连
对于节点 v,在子集 M 中有边与 v 相连,则称节点 v 是由 M 所匹配
否则,节点 v 是没有匹配的
最大匹配 M,即对于任意匹配 M′,均有 ∣M∣⩾∣M′∣
寻找最大二分匹配
初步分析如下
每个节点至少有一条相连的边,所以 ∣E∣⩾∣V∣/2
∣E∣⩽∣E′∣=∣E∣+∣V∣⩽3∣E∣
所以 ∣E′∣=Θ(E)
引理
设 G=(V,E) 是一个二分图,其节点划分是 V=L∪R,不妨设 G′=(V′,E′)
是图 G 对应的流网络。如果 M 是 G 中的一个匹配,则在流网络 G′ 中存在一个整数值的流 f
使得 ∣f∣=∣M∣。相反,如果 f 是 G′ 中的一个整数值的流,同样在 G 中存在一个匹配 M,
使得 ∣M∣=∣f∣
while (q.size()) { int x = q.front(); q.pop(); for (int i = head[x]; i; i = ne[i]) { int y = ver[i]; if (d[y] == -1 && e[i] > 0) { d[y] = d[x] + 1; cur[y] = head[y]; if (y == T) returntrue; q.push(y); } } } returnfalse; }
int dinic(int u, int lim) { if (u == T) return lim; int flow = 0; for (int i = cur[u]; i && lim > flow; i = ne[i]) { cur[u] = i; int v = ver[i]; if (d[v] == d[u] + 1 && e[i]) { int t = dinic(v, min(e[i], lim - flow)); if (!t) d[v] = -1; flow += t, e[i] -= t, e[i^1] += t; } } return flow; }
int dinic() { int res = 0, flow; while (bfs()) { while (true) { flow = dinic(S, inf); if (flow == 0) break; res += flow; } } return res; }
int main() { freopen("input.txt", "r", stdin); scanf("%d%d", &m, &n); S = 0, T = n+1; for (int i = 1; i <= m; i++) add(S, i, 1); for (int i = m+1; i <= n; i++) add(i, T, 1); int a, b; while (scanf("%d%d", &a, &b) && a != -1) add(a, b, 1);
// then solve printf("%d\n", dinic()); for (int i = 2; i <= tot; i += 2) { if (ver[i] > m && ver[i] <= n && e[i] == 0) { printf("%d %d\n", ver[i^1], ver[i]); } } }
const int maxn = 430, maxm = (150 * 270 + maxn) * 2; const int inf = 0x3f3f3f3f; int tot = 0, n, m, S, T; int head[maxn], ver[maxm], e[maxm], ne[maxm], idx = 1;
void add(int a, int b, int c) { ver[++idx] = b; e[idx] = c; ne[idx] = head[a]; head[a] = idx; ver[++idx] = a; e[idx] = 0; ne[idx] = head[b]; head[b] = idx; }
while (q.size()) { int x = q.front(); q.pop(); for (int i = head[x]; i; i = ne[i]) { int y = ver[i]; if (d[y] == -1 && e[i]) { d[y] = d[x] + 1; cur[y] = head[y]; if (y == T) returntrue; q.push(y); } } } returnfalse; }
int dinic(int u, int lim) { if (u == T) return lim; int flow = 0; for (int i = cur[u]; i && lim > flow; i = ne[i]) { cur[u] = i; int v = ver[i]; if (d[v] == d[u] + 1 && e[i]) { int t = dinic(v, min(e[i], lim - flow)); if (!t) d[v] = -1; flow += t, e[i] -= t, e[i^1] += t; } } return flow; }
int dinic() { int res = 0, flow; while (bfs()) while (flow = dinic(S, inf)) res += flow; return res; }
void out() { for (int u = 1; u <= m; u++) { for (int i = head[u]; i; i = ne[i]) { if (ver[i] > m && ver[i] <= n+m && !e[i]) printf("%d ", ver[i]-m); } printf("\n"); } }
int main() { freopen("input.txt", "r", stdin); scanf("%d%d", &m, &n); S = 0, T = m+n+1; for (int i = 1; i <= m; i++) { int r; scanf("%d", &r); add(S, i, r); tot += r; } for (int i = 1; i <= n; i++) { int c; scanf("%d", &c); add(m+i, T, c); } for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) add(i, m+j, 1); }
// then dinic if (dinic() != tot) { printf("0\n"); return 0; }
while (q.size()) { int x = q.front(); q.pop(); for (int i = head[x]; i; i = ne[i]) { int y = ver[i]; if (d[y] == -1 && e[i]) { d[y] = d[x] + 1; cur[y] = head[y]; if (y == T) returntrue; q.push(y); } } } returnfalse; }
int dinic(int u, int lim) { if (u == T) return lim; int flow = 0; for (int i = cur[u]; i && lim > flow; i = ne[i]) { cur[u] = i; int v = ver[i]; if (d[v] == d[u] + 1 && e[i]) { int t = dinic(v, min(e[i], lim - flow)); if (!t) d[v] = -1; flow += t, e[i] -= t, e[i^1] += t; } } return flow; }
int dinic() { int res = 0, flow; while (bfs()) while (flow = dinic(S, inf)) res += flow; return res; }
int main() { freopen("input.txt", "r", stdin); scanf("%d%d", &n, &m); S = 0, T = n+1;
for (int i = 0; i < m; i++) { int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d); add(a, b, c, d); delta[a] -= c, delta[b] += c; } for (int i = 1; i <= n; i++) { if (delta[i] > 0) add(S, i, 0, delta[i]), tot += delta[i]; elseif (delta[i] < 0) add(i, T, 0, -delta[i]); } //debug(tot);
if (dinic() != tot) { puts("NO"); return 0; } puts("YES"); for (int i = 2; i < 2 + m*2; i += 2) { printf("%d\n", e[i^1] + L[i]); } }
有源汇上下界最大流
循环流与具有下界的流 [2020]Douglas B.West, Introduction to Graph Theroy, Second Edition(图论导引原书第二版) chapter 4,定理4.3.20
原网络 G 添加从 t→s 的具有 +∞ 容量的边,此时的网络有个处处守恒的可行流
称为循环流
对于可行循环流 C,在所有节点处引入供应量 σ(xi) 和需求量 ∂(xi),给定流量约束 l(e)⩽f(e)⩽u(e),在每一条边上令 c(e)=u(e)−l(e) f+(v) 表示离开 v 的总流量,f−(v) 表示进入 v 的总流量
while (q.size()) { int x = q.front(); q.pop(); for (int i = head[x]; i; i = ne[i]) { int y = ver[i]; if (d[y] == -1 && e[i]) { d[y] = d[x] + 1; cur[y] = head[y]; if (y == T) returntrue; q.push(y); } } } returnfalse; }
int dinic(int u, int lim) { if (u == T) return lim; int flow = 0; for (int i = cur[u]; i && lim > flow; i = ne[i]) { cur[u] = i; int v = ver[i]; if (d[v] == d[u] + 1 && e[i]) { int t = dinic(v, min(e[i], lim - flow)); if (!t) d[v] = -1; flow += t, e[i] -= t, e[i^1] += t; } } return flow; }
int dinic() { int res = 0, flow; while (bfs()) while (flow = dinic(S, inf)) res += flow; return res; }
int main() { freopen("input.txt", "r", stdin); scanf("%d%d%d%d", &n, &m, &s, &t); S = 0, T = n+1;
for (int i = 0; i < m; i++) { int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d); add(a, b, d-c); A[a] -= c, A[b] += c; } for (int i = 1; i <= n; i++) { if (A[i] > 0) tot += A[i], add(S, i, A[i]); elseif(A[i] < 0) add(i, T, -A[i]); } add(t, s, inf);
// then solve if (dinic() != tot) { puts("No Solution"); return 0; }
int res = e[idx]; e[idx] = e[idx-1] = 0; S = s, T = t; int ans = res + dinic(); printf("%d\n", ans); }
while (q.size()) { int x = q.front(); q.pop(); for (int i = head[x]; i; i = ne[i]) { int y = ver[i]; if (d[y] == -1 && e[i]) { d[y] = d[x] + 1; cur[y] = head[y]; if (y == T) returntrue; q.push(y); } } } returnfalse; }
int dinic(int u, int lim) { if (u == T) return lim; int flow = 0; for (int i = cur[u]; i && lim > flow; i = ne[i]) { cur[u] = i; int v = ver[i]; if (d[v] == d[u] + 1 && e[i]) { int t = dinic(v, min(e[i], lim - flow)); if (!t) d[v] = -1; flow += t, e[i] -= t, e[i^1] += t; } } return flow; }
int dinic() { int res = 0, flow; while (bfs()) while (flow = dinic(S, inf)) res += flow; return res; }
int main() { freopen("input.txt", "r", stdin); scanf("%d%d%d%d", &n, &m, &sc, &tc); S = 0, T = n+1; while (sc--) { int x; scanf("%d", &x); add(S, x, inf); } while (tc--) { int x; scanf("%d", &x); add(x, T, inf); } while (m--) { int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c); } printf("%d\n", dinic()); }