luogu P1345 [USACO5.4] Telecowmunication of dairy cows (graphic skills-"cut point" template, minimum cut)

P1345 [USACO5.4] Telecowmunication
Insert picture description here
minimum cut for dairy cows , we create a super source point and a super sink point, do a minimum cut, and then we can get the minimum of the entire graph into two completely unconnected sets by cutting edges spend.

Similarly, we can also designate two points as the source point and the sink point, and find the minimum cost of cutting the edges so that the two points are no longer connected.
Insert picture description here
(The side weight of the black side is INF, and the side weight of the yellow side is 1)

Image Source

Because we are looking for the minimum number of points to be cut, and our minimum cut is cutting edges, so we can use the point-to-edge transformation technique-cut points, split the points into two, with a weight of 1 in the middle Edge means that we can cut off this edge. We set the weight value of INF for the remaining edges that are even good and cannot be cut so that they will not be cut by mistake.
The last edge cut with the smallest cut is actually that point.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;
int n, m, S, T;

namespace dinic{
    
    

    const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;
    const ll LINF = 0x3f3f3f3f3f;

    int head[N], ver[M], nex[M], tot, cur[N];
    ll edge[M];
    ll maxflow;
    int deep[M];
    int n, m, S, T;

    void add(int x, int y, int z, bool o = 1)
    {
    
    
        ver[tot] = y;
        edge[tot] = z;
        nex[tot] = head[x];
        head[x] = tot ++ ;
        if(o)add(y, x, 0, 0);
    }

    bool bfs(){
    
    
        memset(deep, 0x3f, sizeof deep);
        deep[S] = 0;
        queue<int>q;
        q.push(S);

        while(q.size()){
    
    
            int x = q.front();
            q.pop();

            for(int i = head[x] ; ~i; i = nex[i]){
    
    
                int y = ver[i], z = edge[i];
                if(z > 0 && deep[y] == INF){
    
    
                    q.push(y);
                    deep[y] = deep[x] + 1;
                    cur[i] = head[i];
                    if(y == T)return true;
                }
            }
        }
        return false;
    }

    ll dfs(int x, ll flow)
    {
    
    
        if(x == T)return flow;
        ll ans = 0, i, k;
        for(i = cur[x]; ~i && flow; i = nex[i]){
    
    
            //cur[x] = i;//当前弧优化
            int y = ver[i];
            ll z = edge[i];
            if(z > 0 && deep[y] == deep[x] + 1){
    
    
                k = dfs(y, min(flow, z));
                if(k == 0)deep[y] = INF;
                edge[i] -= k;
                edge[i ^ 1] += k;
                ans += k;
                flow -= k;
            }
        }
        return ans;
    }

    void init(int _n, int _S, int _T)
    {
    
    
        n = _n, S = _S, T = _T;
        memset(head, -1, sizeof head);
        tot = maxflow = 0;
    }

    void main()
    {
    
    
        while(bfs()){
    
    
            for(int i = 1; i <= n; ++ i)
                cur[i] = head[i];
            maxflow += dfs(S, LINF);
        }
    }
}

int main()
{
    
    
    scanf("%d%d%d%d", &n, &m, &S, &T);
    S += n;//从S的出点到T的入点
    dinic::init(2 * n * 10, S, T);

    for(int i = 1;i <= n;++ i){
    
    
        dinic::add(i, i + n, 1);
    }
    for(int i = 1; i<= m; ++i){
    
    
        int x, y;
        scanf("%d%d", &x, &y);//双向图
        dinic::add(x + n, y, INF);
        dinic::add(y + n, x, INF);
    }

    dinic::main();

    printf("%lld\n", dinic::maxflow);
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45697774/article/details/108673267