题目链接:
题目分析:
原本以为是一道裸最小割,仔细一看发现是割点……
把每个点拆成两个点,中间用一条边权为1的边来连接,然后跑最小割即可
注意源点和汇点拆点后的边权要赋为INF,因为不能直接毁坏源点和汇点
代码:
#include<bits/stdc++.h>
#define N (1000 + 5)
#define M (4000 + 5)
#define int long long
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
return cnt * f;
}
int n, m, S, T;
int tot = 1, first[N], nxt[M], to[M], flow[M], dep[N], cnt[N];
void Add(int x, int y, int z) {
nxt[++tot] = first[x], first[x] = tot, to[tot] = y, flow[tot] = z;
}
void bfs_(int s) {
memset(dep, 0xff, sizeof(dep));
dep[s] = 0;
cnt[0] = 1;
queue <int> q;
q.push(s);
while (!q.empty()) {
int p = q.front();
q.pop();
for (register int i = first[p]; i >= 2; i = nxt[i]) {
int v = to[i];
if (dep[v] == -1) {
++cnt[dep[v] = dep[p] + 1];
q.push(v);
}
}
}
}
int max_flow;
int dfs_(int p, int f) {
if (p == T + n) {
// cout<<"qwq"<<f<<endl;
max_flow += f;
return f;
}
int u = 0;
for (register int i = first[p]; i >= 2; i = nxt[i]) {
int v = to[i];
if (flow[i] && dep[v] == dep[p] - 1) {
int uu = dfs_(v, min(flow[i], f - u));
if (uu) {
flow[i] -= uu;
flow[i ^ 1] += uu;
u += uu;
}
if (u >= f) return u;
}
}
if (!--cnt[dep[p]]) dep[S] = 2 * n + 1;
++cnt[++dep[p]];
return u;
}
int x, y;
signed main() {
n = read(); m = read(); S = read(); T = read();
for (register int i = 1; i <= n; i++) {
if (i == S || i == T) continue;
Add(i, i + n, 1), Add(i + n, i, 0);
}
Add(S, S + n, 0x3FFFFFFF), Add(S + n, S, 0);
Add(T, T + n, 0x3FFFFFFF), Add(T + n, T, 0);
for (register int i = 1; i <= m; i++) {
x = read(); y = read();
Add(x + n, y, 0x3FFFFFFF);
Add(y, x + n, 0);
Add(y + n, x, 0x3FFFFFFF);
Add(x, y + n, 0);
}
bfs_(T + n);
while (dep[S] < 2 * n) dfs_(S, 0x3FFFFFFF);
printf("%lld", max_flow);
return 0;
}