[USACO5.4]奶牛的电信Telecowmunication(最小割点)

题目链接
题意:给你一个无向图,问最少割去多少个点使源点和汇点不连通。
思路:问的是割点啊,就不能直接用最大流求最小割,因为内求的是割边。所以这里需要将点拆分成由一条有向边链接的两个点(其中所有入度的边连接原点,所有出度的边连接拆出来的点,原点和拆出来的点间由一条权值为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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值