[洛谷P1345] [USACO5.4]奶牛的电信Telecowmunication

题目链接:

奶牛的电信

题目分析:

原本以为是一道裸最小割,仔细一看发现是割点……

把每个点拆成两个点,中间用一条边权为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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值