网络流自学心得[day01]

匹配问题终于可以告一段落,虽然还不是很通透,但时间不允许了。
接下来我们来看看网络流的问题,这个东西和匹配还是有一点相似的,但是也好难。
第一天我们就来讲讲最大流 和 ek算法。。(虽然这个算法在竞赛中基本不用)

- 最大流问题

我们的网络流从最大流开始。那什么是最大流呢?
图A
如上图所示,假设我们现在要把一些物品从结点s(称为源点)运送到结点t(称为汇点),可以从其他结点中转,问能够到达t点的物品的最大值。

这样的问题就被叫做最大流问题,对于一条边(u,v)[u为起点,v为终点],他的物品上限称为容量,记为c(u,v)(对于不存在的边(u,v),c(u,v) = 0);实际运送的物品我们称为流量,记为f(u,v)。在这里的流量是一个总称,即把所有的流进流出都已经加在了一起。即将3个物品从u运送到了v,又把5个物品从v运送到了u,这就等价于我们把两个物品从v运送到了u,所以将某一个结果分成多个情况的相加是没有意义的。这样,我们就可以规定f(u,v)和f(v,u)最多只有一个是整数,也可以都是0。并且f(u,v) = - f(v,u)。

问题的目标

我们的目标是把尽可能多的物品从s运送到t,而其他结点都只是中转。因此对于除了s和t意外的任意节点u,他的流入始终是等于流出的。从s中运送出来的物品数量得那个鱼到达t的物品数量,而这正是此处最大化的目标。即求出maxflow
而在这样的问题中,容量c和流量f满足了3个性质

1.容量限制 -----> f(u,v) <= c(u,v)
2.斜对称性 -----> f(u,v) = - f(v,u)
3.流量平衡 -----> 指的就是对于除了结点s和t外的其余结点,流入等于流出。

我们也可以说,当一个图满足了这三个性质,我们把它当做一个网络流的模型来对待。

算法:增广路算法

我们从零流(所有边的流量均为0)开始不断增加流量,但在这个同时,我们让每一个点都满足以上三个性质,直到增加到一个最大的流,我们再也不能增加流除非打破这三个性质为止。
这就是增广路算法的基础思想,在这个思想上加上BFS, 我们就得到了Edmonds-Karp算法。

Edmonds-Karp算法

我们先来叙述几个概念。
容量 :上面讲过了。
流量: 即实际上你给这条边流的量
残量: 容量-流量。

增广:求出该道路中所有残量的最小值d,把对应的所有边上的流量减去d。
当且仅当残量网络中不存在增广路,那么此时的流就是最大流。
下面给出ek最简单粗暴的代码,而且这里的存图用的是二维数组的形式。当然这种形式在很多时候就会爆栈,但只要理解了这个,用其他的存图方式也不难解决。
这里再给出一个模板题,用二维数组一定爆栈,但是用其他存图方式就能过
最大流模板题

int N, M ,S ,T;//N个点,M条边,S是起点位置,T是终点位置
int a, b, c;//a为u, b为v, c为c(u,v)
int w[len][len], flow[len][len];w为总图,flow为流量图
int pre[len], res[len], maxflow ;//pre数组记录每一个点的前驱,返回时用  res数组表示余量
int main(){
    memset(w, 0, sizeof(w));
    cin >> N >> M >> S >> T;
    for(int i=1; i<=M; i++){
        cin >> a >> b >> c;
        w[a][b] +=c;
    }

    int ans = Edmonds_Karp(S,T);

    cout << ans << endl;
    return 0;
}

int Edmonds_Karp(int start, int End){
    maxflow = 0;
    memset(flow, 0, sizeof(flow));
    memset(pre, 0, sizeof(pre));
    queue <int> q;
    while (true){
        memset(res, 0, sizeof(res));
        res[start] = INF;//第一个点我们给上无穷大的货,这样他就能运出他最多的量了。
        q.push(start);
        while(!q.empty()){
            int h = q.front();q.pop();

            for (int i=1; i<=N; i++){
                if (!res[i] && w[h][i]>flow[h][i]){//如果余量不是0,就说明这个点我们流过了。一条路一条路找
                    res[i] = min(res[h], w[h][i] - flow[h][i]);
                    pre[i] = h;
                    q.push(i);
                }
            }
        }

        if (!res[End]) return maxflow;//若果最后一个点没有余量了,那就说明已经没有留下的了。

            for (int i=End; i!=start; i=pre[i]){
                flow[pre[i]][i] += res[End];
                flow[i][pre[i]] -= res[End];
            }
            maxflow += res[End];
    }
}

这里才给出一个厉害的博主写的厉害的博客
EK算法详解

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值