网络流模板

定义:

1. 流网络:不考虑反向边,若存在反向边可以加一个点使其变得不存在反向边

2. 可行流:需要满足容量限制(0 <= f(u,v) <= c(u,v) )和流量守恒

3. 流量:从源点流出的流量减去流进原点的流量

4. 残留网络:对于流网络中的某一条可行流来说的(点等于原网络的所有点,边为原网络的边和原网络的反向边)【有可行流的概念】(只有在残留网络中才会考虑反向边)

        原网络的流量(f) + 残留网络的流量(f') 也是 原网络的流量

5. 增广路径:从原点开始沿着容量大于0的边开始走,走到终点的路径(流量大于0的可行流)

6. 割:将原网络的点集分成两个子集S和T(相交为空,且s属于S,t属于T)

7. 割的容量:从S指向T的容量之和(割的分法一共有2的n-2次方种)

8. 割的流量:从S指向T的流量 - 从T指向S的流量

9. 最大流:最大可行流的流量   最小割:指的是最小割的容量

10. 对于任意一个可行流任意割,割的流量都等于该可行流的流量

最大流最小割定理:

1. 可行流f是最大流

2. 可行流f的残留网络中不存在增广路

3. 存在某个割[S,T], |f| = c(S, T)

证明建图是正确的:1.原网络的可行流都是原问题的一个可行解 2. 原问题的一个可行解都是原网络的可行流

模板

EK(时间复杂的 n*m*m)【n=1000 ~ 10000】

#include<bits/stdc++.h>
using namespace std;
const int N = 1010, M = 20010;
const int INF = 1e9;
int n, m, S, T;

// 存的是残留网络的图
int e[M], ne[M], h[M], f[M], idx;
void add(int u, int v, int c){
    e[idx] = v, ne[idx] = h[u], f[idx] = c, h[u] = idx++; // f为容量
    e[idx] = u, ne[idx] = h[v], f[idx] = 0, h[v] = idx++;
}

bool st[N];
int q[N], d[N], pre[N];
bool bfs(){
    int hh = 0, tt = 0;
    memset(st, false, sizeof st);
    q[0] = S, st[S] = true, d[S] = INF;
    while(hh <= tt){
        int u = q[hh++];
        for(int i = h[u]; ~i; i = ne[i]){
            int v = e[i];
            if(!st[v] && f[i]){
                st[v] = true;
                d[v] = min(d[u], f[i]);
                pre[v] = i;
                if(v == T) return true;
                q[++ tt] = v;
            }
        }
    }
    return false;
}

int EK(){
    int res = 0;
    while(bfs()){ // 找增广路劲
        res += d[T];
        for(int i = T; i != S; i = e[pre[i] ^ 1])
            f[pre[i]] -= d[T], f[pre[i] ^ 1] += d[T]; // 更新残留网络
    }
    return res;
}

int main(){
    memset(h, -1, sizeof h);
    scanf("%d%d%d%d", &n, &m, &S, &T);
    for(int i = 1; i <= m; i++){
        int u, v, c;
        scanf("%d%d%d", &u, &v, &c);
        add(u, v, c);
    }
    printf("%d\n", EK());
    return 0;
}

dinic(时间复杂度n*n*m)【n=10000 ~ 100000】

#include<bits/stdc++.h>
using namespace std;
const int N = 10010, M = 200010;
const int INF = 1e9;
int n, m, S, T;

int e[M], ne[M], h[M], f[M], idx;
void add(int u, int v, int c){
    e[idx] = v, ne[idx] = h[u], f[idx] = c, h[u] = idx++; // f为容量
    e[idx] = u, ne[idx] = h[v], f[idx] = 0, h[v] = idx++;
}

int d[N], q[N], cur[N];
bool bfs(){
    int hh = 0, tt = 0;
    memset(d, -1, sizeof d);
    q[0] = S, d[S] = 0, cur[S] = h[S];
    while(hh <= tt){
        int u = q[hh++];
        for(int i = h[u]; ~i; i = ne[i]){
            int v = e[i];
            if(d[v] == -1 && f[i]){
                d[v] = d[u] + 1;
                cur[v] = h[v];
                if(v == T) return true;
                q[++tt] = v;
            }
        }
    }
    return false;
}

int find(int u, int limit){
    if(u == T) return limit;
    int flow = 0;
    for(int i = cur[u]; ~i && flow < limit; i = ne[i]){
        cur[u] = i; // 当前弧优化
        int v = e[i];
        if(d[v] == d[u] + 1 && f[i]){
            int t = find(v, min(f[i], limit - flow));
            if(!t) d[v] = -1;
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

int dinic(){
    int res = 0, flow;
    while(bfs()) while(flow = find(S, INF)) res += flow;
    return res;
}

int main(){
    memset(h, -1, sizeof h);
    scanf("%d%d%d%d", &n, &m, &S, &T);
    for(int i = 1; i <= m; i++){
        int u, v, c;
        scanf("%d%d%d", &u, &v, &c);
        add(u, v, c);
    }
    printf("%d\n", dinic());
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值