[网络流]最大流模板

网络流最大流最小割

题目链接

就是一道点割最小割模板。

找了许久的模板,终于遇到了

先说边割

边割比较常见。

最大流

最大流等于最小割,我懒得证。

求最大流的思路就是每次尝试找一条从源点到汇点的通路,然后找到这条路上残余流量最小的流量,答案加上这个流量,这条通路上每条边的残余流量减去这个值,反向边加上这个值。

关于反向边,实际上是一个反悔机制。反向流多少,表示正向已经流了多少。也就是说,如果我们从反向边流了一些流量,就相当于从这条边退回了一部分流量。

点割

所谓点割,就是被割掉的不再是边,而是点。思路是将点转化成边。

如上题:将每个点拆成\(i\)\(i+n\)两个点,中间连一条流量为\(1\)的边,将这条边割掉,就相当于割掉这个点。

详见代码。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
long long read(){
    long long x = 0; int f = 0; char c = getchar();
    while(c < '0' || c > '9') f |= c == '-', c = getchar();
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f ? -x:x;
}

const int INF = 2147483647;
int n, m, s, t;
struct szh{
    int nxt, to, w;
}a[4004];
int head[203],cnt=1;
void add(int x, int y, int w){
    a[++cnt].nxt = head[x], a[cnt].to = y, head[x] = cnt, a[cnt].w = w;
}

int dis[203];
bool bfs(){
    memset(dis, 0, sizeof dis);
    queue<int> q;
    q.push(s), dis[s] = 1;
    while(!q.empty()){
        int u = q.front();q.pop();
        for (int i = head[u], v; v = a[i].to, i; i = a[i].nxt)
            if(a[i].w && !dis[v]) q.push(v), dis[v] = dis[u] + 1;
    }
    return dis[t];
}

int fir[103];
int dfs(int u, int flow){
    if(u == t || !flow) return flow;
    int ans = 0;
    for (int &i = fir[u], v; v = a[i].to, i; i = a[i].nxt)
        //弧优化
        if(a[i].w && dis[v] == dis[u] + 1){
            int x = dfs(v, min(flow, a[i].w));
            a[i].w -= x, a[i^1].w += x, ans += x; //更新残余流量
            if(!(flow-=x)) break;
        }
    return ans;
}

void dinic(){
    int ans = 0;
    while(bfs()){
        for (int i = 1; i <= (n << 1); ++i) fir[i] = head[i];
        //为dfs中取址操作做铺垫
        ans += dfs(s,INF);
    }
    printf("%d", ans);
}

int main(){
    n = read(), m = read(), s = read(), t = read();
    s += n; //源点不能删掉
    for (int i = 1; i <= n; ++i) add(i, i + n, 1), add(i + n, i, 0);
    //拆点
    for (int i = 1; i <= m; ++i){
        int x = read(), y = read();
        add(x + n, y, INF), add(y, x + n, 0); //电脑之间不会断,所以连INF
        add(y + n, x, INF), add(x, y + n, 0);
    }
    dinic(); //模板
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kylinbalck/p/10590252.html