最小割
概念一:割
对于一个网络流图\(G=(V,E)\),割为一种将其划分为两端互不关联的区域的方式,其定义为点的划分方式:将所有点划分\(S\)和\(T=V-S\)两个集合,源点\(s\in S\)汇点\(t\in T\)。
概念二:割的容量
我们定义割\((S,T)\)的容量就是所有从S到T的边的容量和,即:\(c(S,T)=\Sigma _{u\in S,v\in T}c(u,v)\)。
那么最小割就是:使割的容量最小的割的方法。(求出一个割使之容量最小)
最大流最小割定理
定理:\(f(s,t)_{max}=c(s,t)_{min}\)
首先:对于任意一个可行流\(f(s,t)\)的割\((S,T)\),可以肯定的是:
\[f(s,t)=S_{出流量}-S_{入流量}\le S_{出流量}=c(S,T)
\]
所以我们可以发现:当我们去到最大流时,残量网络中一定没有增广路了,那么此时:
\[f(s,t)=S_{出流量}-S_{入流量}=c(S,T)
\]
结合不等式,此时最小割便求出来了。
代码:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
const int N = 1e4 + 5, M = 2e5 + 5;
int n, m, s, t, tot = 1, lnk[N], ter[M], nxt[M], val[M], dep[N], cur[N];
void add(int u, int v, int w) {
ter[++tot] = v, nxt[tot] = lnk[u], lnk[u] = tot, val[tot] = w;
}
void addedge(int u, int v, int w) { add(u, v, w), add(v, u, 0); }
int bfs(int s, int t) {
memset(dep, 0, sizeof(dep));
memcpy(cur, lnk, sizeof(lnk));
std::queue<int> q;
q.push(s), dep[s] = 1;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = lnk[u]; i; i = nxt[i]) {
int v = ter[i];
if (val[i] && !dep[v]) q.push(v), dep[v] = dep[u] + 1;
}
}
return dep[t];
}
int dfs(int u, int t, int flow) {
if (u == t) return flow;
int ans = 0;
for (int &i = cur[u]; i && ans < flow; i = nxt[i]) {
int v = ter[i];
if (val[i] && dep[v] == dep[u] + 1) {
int x = dfs(v, t, std::min(val[i], flow - ans));
if (x) val[i] -= x, val[i ^ 1] += x, ans += x;
}
}
if (ans < flow) dep[u] = -1;
return ans;
}
int dinic(int s, int t) {
int ans = 0;
while (bfs(s, t)) {
int x;
while ((x = dfs(s, t, 1 << 30))) ans += x;
}
return ans;
}
int main() {
scanf("%d%d%d%d", &n, &m, &s, &t);
while (m--) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
}
printf("%d\n", dinic(s, t));
return 0;
}
割去边的数量:
只需要将每条边的容量变为1 ,然后重新跑 即可最大流。