题目链接
题意:给你一个无向图,问最少割去多少个点使源点和汇点不连通。
思路:问的是割点啊,就不能直接用最大流求最小割,因为内求的是割边。所以这里需要将点拆分成由一条有向边链接的两个点(其中所有入度的边连接原点,所有出度的边连接拆出来的点,原点和拆出来的点间由一条权值为1的有向边相连,因为一个点只能够被删除一次)。那么对于每一条无向边,相当于我们要补成一个环。将点拆分完后直接跑最大流求出拆点后的最小割即可。需要注意的是源点和汇点肯定是不能删除的所以源点和汇点拆分后连接两个点的边边权赋为inf。
ac代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define int long long
int cnt[205][205];
int flow[205], pre[205];
int n, m, s, t;
int inf = 0x7f7f7f7f;
queue<int> kk;
int bfs(int a, int b) {
while (!kk.empty()) kk.pop();
memset(pre, 0, sizeof(pre));
kk.push(a), pre[a] = -1, flow[a] = inf;
while (!kk.empty()) {
int ll = kk.front(); kk.pop();
if (ll == b) break;
for (int i = 1; i <= 2*n; i++) {
if (i != a && cnt[ll][i] > 0 && pre[i] == 0) {
pre[i] = ll;
flow[i] = min(flow[ll], cnt[ll][i]);
kk.push(i);
}
}
}
if (pre[b] == 0) return -1;
return flow[b];
}
int EK(int a, int b) {
int mm = 0, tot = 0;
while (1) {
int mm = bfs(a, b);
if (mm == -1) break;
tot += mm;
int p = b;
while (p != a) {
cnt[p][pre[p]] += mm;
cnt[pre[p]][p] -= mm;
p = pre[p];
}
}
return tot;
}
signed main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m >> s >> t;
for (int i = 0; i < m; i++) {
int a, b; cin >> a >> b;
cnt[a][a + n] = 1; cnt[a + n][b] = inf; cnt[b][b + n] = 1; cnt[b+n][a] = inf;//拆点
}
cnt[s][s + n] = inf; cnt[t][t + n] = inf;//源点和汇点不能删
int ans = EK(s, t);
cout << ans << endl;
return 0;
}