zoukankan      html  css  js  c++  java
  • 网络流,再出发!

    之前虽然刷了大概一百道网络流的题目,但是始终是把网络流当作黑盒算法来学。我大概知道了网络流能做什么。

    但是对于网络流的代码细节我还是一窍不通。特此写一篇博文来整理,我对网络流的理解。

    Ford-Fulkerson算法:

    这个算法是一切网络流算法的基础,其最重要的贡献就是增广路定理:找不到增广路的时候,此时的累加流量就是最大流。

    所以这个算法最主要的地方就是寻找增广路——每次DFS寻找从S到T路径上流量最小的边。

    之后便是残余网络的概念。每次找到增广路之后都修改残余网络。直到不存在增广路的时候,算法结束。

    缺陷:因为每次都是dfs所以,太不稳定,会被值域所影响。如下图,图片源自https://www.cnblogs.com/rvalue/p/10650849.html

    有可能会在1-2之间进行466666666次过程。

    Edmonds-Karp算法:

    EK算法是上面算法的多项式优化版本。最主要的地方就是用BFS代替了DFS使得每次增广的都是最短路

     图片源自上面链接。

    局限:EK算法的劣势就在于, 每次遍历了一遍残量网络之后只能求出一条增广路来增广。

    Dnic算法:

    相较于EK算法,Dinic的复杂度更为优秀。Dinic最重要的思想就是引入了分层图,让流只能往下一层流

    每次跑DFS都能实现多路增广,增广完之后重新BFS建分层图。一旦建不了分层图那么算法结束。

    其中我们说说Dinic代码细节。(BFS就是裸的分层,所以主要是DFS)

    inline ll dfs(int u, ll flow) {
        if(u == T) return flow;
        ll del = flow;
        for(int i = cur[u]; ~i; i = edge[i].next){
            cur[u] = edge[i].next;//当前弧优化,下次直接从cur[u]开始增广,节省时间
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].w > 0){//深度+1且残量大于0
                ll ans = dfs(v, min(del, edge[i].w));//木桶原理
                edge[i].w -= ans;//正向弧减增广流量
                edge[i ^ 1].w += ans;//反向弧加增广流量
                del -= ans;//总流量减增广流量
                if(del == 0) break;//总流量为0则不继续增广
            }
        }
        return flow - del;//返回本次增广的流量
    }
    当前弧优化:每次DFS都会访问一些边,当前弧优化就是让你DFS的时候直接从不重复的地方开始。
    del优化:为什么要设计一个del,通过flow-del来返回增广流量呢?我的理解是,del的意义是可行上界,意思就是有这么多流量流进来。那么我们很容易知道当上界为0的时候肯定就不能增广了,所以直接break。
     
  • 相关阅读:
    git撤销操作总结
    pull request的一些思考
    设计模式之门面模式
    设计模式之策略模式
    java中的堆栈
    git冲突的处理
    Eclipse 未正常退出,导致进不去的问题
    think in java读后总结---Map集合的几种遍历方式
    maven打包后项目名称不对
    python之正则表达式
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/13645508.html
Copyright © 2011-2022 走看看