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

Description

给定一张 n n n m m m 边的无向图,求最少要删去几个点,才能使 c 1 c1 c1 c 2 c2 c2 不连通?

Analysis

总所周知,边的最小割 可以转化为最大流求解。
但这题求的是 点的最小割,我们就要想办法转化成 边的最小割

我们使用 拆点 的思想,将每一个点都拆成一个入点和一个出点,中间连一条权值为 1 1 1 的边,这样,只要删去这条边,就相当于删掉这个点。

题目中给的边,以及 c 1 c1 c1 c 2 c2 c2 的内部边,边权显然为 ∞ \infty 。(因为题目要求删点,另外 c 1 c1 c1 c 2 c2 c2 都不能删)。

然后在新图上跑最小割即可。

Code

最大流模板是贴的 jiangly 的。

// Problem: P1345 [USACO5.4] 奶牛的电信Telecowmunication
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1345
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
const int INF = 1e9;

template<class T>
struct MaxFlow {
    struct _Edge {
        int to;
        T cap;
        _Edge(int to, T cap) : to(to), cap(cap) {}
    };
    
    int n;
    T inf;
    std::vector<_Edge> e;
    std::vector<std::vector<int>> g;
    std::vector<int> cur, h;
    
    MaxFlow() {}
    MaxFlow(int n) {
        init(n);
        inf = numeric_limits<T>::max();
    }
    
    void init(int n) {
        this->n = n;
        e.clear();
        g.assign(n, {});
        cur.resize(n);
        h.resize(n);
    }
    
    bool bfs(int s, int t) {
        h.assign(n, -1);
        std::queue<int> que;
        h[s] = 0;
        que.push(s);
        while (!que.empty()) {
            const int u = que.front();
            que.pop();
            for (int i : g[u]) {
                int v = e[i].to;
                T c = e[i].cap;
                if (c > 0 && h[v] == -1) {
                    h[v] = h[u] + 1;
                    if (v == t) {
                        return true;
                    }
                    que.push(v);
                }
            }
        }
        return false;
    }
    
    T dfs(int u, int t, T f) {
        if (u == t) {
            return f;
        }
        auto r = f;
        for (int &i = cur[u]; i < int(g[u].size()); ++i) {
            const int j = g[u][i];
            int v = e[j].to;
            T c = e[j].cap;
            if (c > 0 && h[v] == h[u] + 1) {
                auto a = dfs(v, t, std::min(r, c));
                e[j].cap -= a;
                e[j ^ 1].cap += a;
                r -= a;
                if (r == 0) {
                    return f;
                }
            }
        }
        return f - r;
    }
    void addEdge(int u, int v, T c) {
        g[u].push_back(e.size());
        e.emplace_back(v, c);
        g[v].push_back(e.size());
        e.emplace_back(u, 0);
    }
    T flow(int s, int t) {
        T ans = 0;
        while (bfs(s, t)) {
            cur.assign(n, 0);
            ans += dfs(s, t, std::numeric_limits<T>::max());
        }
        return ans;
    }
    
    std::vector<bool> minCut() {
        std::vector<bool> c(n);
        for (int i = 0; i < n; i++) {
            c[i] = (h[i] != -1);
        }
        return c;
    }
    
    struct Edge {
        int from;
        int to;
        T cap;
        T flow;
    };
    std::vector<Edge> edges() {
        std::vector<Edge> a;
        for (int i = 0; i < e.size(); i += 2) {
            Edge x;
            x.from = e[i + 1].to;
            x.to = e[i].to;
            x.cap = e[i].cap + e[i + 1].cap;
            x.flow = e[i + 1].cap;
            a.push_back(x);
        }
        return a;
    }
};
  

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    
    int n, m, c1, c2;
    cin >> n >> m >> c1 >> c2;
    c1--, c2--;
    
    MaxFlow<int> G(n << 1);
    
    for(int i = 0; i < n; i++){
        if(i == c1 || i == c2) G.addEdge(i, i + n, INF);
        else G.addEdge(i, i + n, 1);
    }
    
    for(int i = 0, u, v; i < m; i++){
        cin >> u >> v;
        u--, v--;
        G.addEdge(u + n, v, INF);
        G.addEdge(v + n, u, INF);
    }
    cout << G.flow(c1, c2) << endl;
    return 0;
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值