AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

最大流

作者: 作者的头像   Lemmon_kk ,  2020-07-24 09:29:52 ,  所有人可见 ,  阅读 646


4


3
1. 最大流等于最小割
2. 可行流 <= 最大流 = 最小割 <= 任意割
3. 每次找增广路 // 至于为什么不全部一次性找完 而是每次找一个呢 可以参考星空大佬的博客
4. 网络流的时间复杂度一般是不会到理论上限的 就算超时加上 多路增广优化 和 炸点优化即可

3问题的参考 orz

// Ford-Fulkerson (链式前向星)
void add(int a,int b,int c){
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
    e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ;
}

int dfs(int x,int flow){
    if(x == t) return flow; // 走到汇点 返回本次增广流量
    vis[x] = 1;
    for(int i = h[x];~i;i = ne[i]){
        int j = e[i];
        if(w[i] && !vis[j]){
            int t = dfs(y, min(flow, w[i]));
            if(t > 0){
                w[i] -= t, w[i ^ 1] += t;
                return t;
            }
        }
    }
    return 0;
}

while(memset(vis, 0, sizeof vis) && (res = dfs(s, 2e9)) > 0) ans += res;

printf("%d\n", ans);
----------------
// Dinic 对 FF 分层图优化
int s, t, flow;

bool bfs(){
    memset(d, 0, sizeof d);
    while(q.size()) q.pop();

    d[s] = 1; q.push(s);
    while(q.size()){
        auto t = q.front(); q.pop();
        for(int i = h[t];~i;i = ne[i]){
            // 有残留网络 并且没有被遍历过
            if(w[i] && !d[e[i]]){
                d[e[i]] = d[t] + 1;
                q.push(e[i]);
                if(e[i] == t) return 1; // 能到终点
            }
        }
    }
    return 0; // 不连通 即st割为0
}

int dinic(int x,int flow){
    if(x == t) return flow;
    int sum = 0;
    for(int i = h[x];~i;i = ne[i]){
        int j = e[i];
        if(w[i] && d[j] == d[x] + 1){
            int k = dinic(j, min(flow, w[i]));
            w[i] -= k, w[i ^ 1] += k;
            flow -= k, sum += k;
        }
    }

    if(!sum) d[x] = 0;
    return sum;
}

while(bfs())
    while(flow = dfs(s, 2e6))
        ans += flow;
// Dinic 当前弧优化
// 当一个点被榨干的时候 就把它删掉
int s, t, flow;
int cur[N];

bool bfs(){
    memcpy(cur, h, sizeof h);
    memset(d, 0, sizeof d);
    while(q.size()) q.pop();

    d[s] = 1; q.push(s);
    while(q.size()){
        auto t = q.front(); q.pop();
        for(int i = h[t];~i;i = ne[i]){
            // 有残留网络 并且没有被遍历过
            if(w[i] && !d[e[i]]){
                d[e[i]] = d[t] + 1;
                q.push(e[i]);
                if(e[i] == t) return 1; // 能到终点
            }
        }
    }
    return 0; // 不连通 即st割为0
}

int dinic(int x,int flow){
    if(x == t) return flow;
    int sum = 0;
    for(int i = cur[x];~i;i = ne[i]){
        cur[x] = i; // 当前弧优化
        int j = e[i];
        if(w[i] && d[j] == d[x] + 1){
            int k = dinic(j, min(flow, w[i]));
            w[i] -= k, w[i ^ 1] += k;
            flow -= k, sum += k;
        }
    }

    if(!sum) d[x] = 0; // 炸点优化
    return sum;
}

while(bfs())
    while(flow = dfs(s, 2e6))
        ans += flow;

// 多路增广优化
int dinic(int x,int flow){
    int a;
    if(x == t) return flow;
    int cost = 0;
    for(int &i = h[x];~i;i = ne[i]){
        int v = e[i];
        int r = w[i];
        if(d[v] == d[x] + 1 && w && (a = dfs(v, min(flow - cost, r)))){
            w[i] -= a, w[i ^ 1] += a;
            cost += a; // 汇聚各个方向的流量
            if(flow == cost) // 当某几个方向的流量相加等于当前最大流量的时候就无法对别的路进行增广了
                break;
        }
    }
    return cost;//返回当前汇聚的流量
}

EK

#define INF 0x3f3f3f3f
const int N = 10010;

int g[N][N], flow[N], pre[N];
int n, m;
queue<int> q;

int bfs(int s,int t){
    while(q.size()) q.pop();
    memset(pre, -1, sizeof pre);
    pre[s] = 0, flow[s] = INF;
    q.push(s);
    while(q.size()){
        int p = q.front(); q.pop();
        if(p == t) break;
        for(int i = 1;i <= n;i ++ ){
            if(i != s && pre[i] != -1 && g[p][i] > 0){
                pre[i] = p;
                flow[i] = min(flow[p], g[p][u]);
                q.push(i);
            }
        }
    }

    if(pre[t] == -1) return -1;
    return flow[t];
}

int EK(int s,int t){
    int sum = 0, delta = 0;
    while(1){
        delta = bfs(s, t);
        if(delta == -1) break; // 无增广路
        int p = t;
        while(p != s){
            g[pre[p]][p] -= delta;
            g[p][pre[p]] += delta;
            p = pre[p];
        }
        sum += delta;
    }

    return sum;
}

int ans = EK(1, n);

最小费用流(其实就是换成spfa就行)

3 评论


用户头像
hulwang   2020-10-20 07:51         踩      回复

void add(int a,int b,int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ;
e[idx] = c, w[idx] = 0, ne[idx] = h[b], h[b] = idx
;
} 写错了吧 第二个 e[idx] 应该是 e[idx] = a

用户头像
Lemmon_kk   2020-10-20 11:08         踩      回复

是的hh,感谢指正


用户头像
cht   2020-07-24 10:36         踩      回复

wowow


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息