• 题解 Luogu P3376 【【模板】网络最大流】


    本人很弱,只会Dinic、EK与Ford-Fulkerson...(正在学习ISAP...)

    这里讲Dinic...

    Dinic:与Ford-Fulkerson和的思路相似(话说好像最大流求解都差不多吧),也是使用深搜寻找增广路(至于增广路是什么,只要在学最大流而不是借鉴他人代码的应该都知道吧)。

    但是(划重点),Dinic有一个十分不一样的地方(Dinic:我们不一样,不一样!),就是还用了**BFS**(是为了凑齐深搜广搜召唤神龙)!

    BFS有什么用呢,除了使时间复杂度更上一层楼之外,还有什么用呢?

    这就是Dinic的神奇之处了,BFS反而使时间复杂度降低,与EK看似肩并肩(EK:O(nm^2) Dinic:O(n^2m))。看上去是肩并肩了,实则在题目上,Dinic基本都比EK优秀,特别是二分图。

    扯远了,继续讲Dinic的BFS的用处。

    BFS是为了划分等级周朝的分封制!),使得在找增广路时跳过一些对这条增广路没用的点,使DFS效率大大提高。

    另外,代码还可以加上当前弧优化与多路增广使其更快。

    多路增广,设置一个变量used,记录这条边的流量,就不用搜到就退了,最后满了再退出。

    当前弧优化:设置一个数组,在BFS预处理中将它赋值head[i],就相当于邻接表里的head,但是(划重点)它的值是随着增广的时候所变小的,然后下次增广时就可以跳过已经用过的边。

    献上我丑陋的代码:

    #include<cstdio>
    #define INF 0x3f3f3f3f
    #define maxn 3000001
    inline int read(){//快读
        int r=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            r=r*10+c-'0';
            c=getchar();
        }
        return r*f;
    }
    void write(int x)//快速输出
    {
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    struct edge{
        int v,c,nxt;
    }e[2*maxn];
    //struct max_Fow{//本来写了结构体的
        int S,T,N,head[maxn],q[maxn],cur[maxn],level[maxn],tot=0,hd,tl,v;
        inline void init(int s,int t,int n){//为结构体而写
            S=s;
            T=t;
            N=n+1;
            for(register int i=1;i<N;i++)//想想为什么不直接为0
                head[i]=-1;
        }
        inline void add_edge(int u,int v,int c){
            e[tot]=(edge){v,c,head[u]};//为什么从0开始?
            head[u]=tot++;
        } 
        inline void add(int u,int v,int c){
            add_edge(u,v,c);
            add_edge(v,u,0);//反向边
        }
        inline bool BFS(){
            for(register int i=1;i<N;i++){
                cur[i]=head[i];//当前弧优化初始化
                level[i]=0;//等级初始化
            }
            q[1]=S;
            level[S]=1;
            hd=0;tl=1;
            while(hd^tl){//广搜
                hd++;
                for(register int i=head[q[hd]];i!=-1;i=e[i].nxt){
                    if(e[i].c&&!level[e[i].v]){
                        tl++;
                        level[e[i].v]=level[q[hd]]+1;
                        q[tl]=e[i].v;
                        if(e[i].v==T)return true;//搜到就退
                    }
                }
            }
            return false;//否则无法拓展到汇点
        }
        inline int min(int a,int b){//手写min
            if(a<b)return a;
            return b;
        }
        int DFS(int f,int u){
            if(u==T)return f;
            int d=0,used=0;//多路增广
            for(int &i=cur[u];i!=-1;i=e[i].nxt){//当前弧优化
                if(e[i].c&&level[u]==level[e[i].v]-1){
                    if((d=DFS(min(f-used,e[i].c),e[i].v))){
                        e[i].c-=d;
                        e[i^1].c+=d;//为什么可以直接这样?
                        used+=d;//多路增广
                    }
                }
            }
            if(!used)level[u]=0;
            return used;
        }
        inline int Dinic(){//求解
            int max_flow=0;
            while(BFS()){
                int d=0;
                while((d=DFS(INF,S)))
                    max_flow+=d;
            }
            return max_flow;
        }
    //}Flow;
    int main(){
        int n=read(),m=read(),s=read(),t=read(),i;
        /*Flow.*/init(s,t,n);
        for(i=1;i<=m;i++){
            int a=read(),b=read(),v=read();
            /*Flow.*/add(a,b,v);
        }
        int ans=/*Flow.*/Dinic();
        write(ans);
        return 0;
    }

    Q:为什么head[]初始值为-1更好?

    A:因为开始值就会为0,xor1就等于+1或-1,那样又会少了一些判断,

    并且,Dinic也可以做费用流,只要将广搜换为SPFA就行了

    完结撒花!!!✿✿ヽ(°▽°)ノ✿

  • 相关阅读:
    .net 中 数据库的查询参数写法。微软其他开发环境同理
    【开源】女人值钱计算器,C++
    远程桌面的端口修改
    .net 中使用ActiveX控件的自动创建的包装器的问题(自动生成的Interop.Ax*Lib.dll)
    ASP.NET站点的同时部署给不同的客户。通过数据库配置站点的Top、版权、站点名称
    当下常见的十大(现在补充了,是十一大手机操作系统)手机(平板)操作系统
    项目外包,类似QQ这样界面的客户端,要求界面漂亮,功能是帮助客户完成在线业务的功能。
    stdoled.dll 的问题
    dotnet调用外部dll中,参数数据类型的问题
    前两天用VC6做的修改远程桌面端口的命令行小程序,源码。
  • 原文地址:https://www.cnblogs.com/wyzwyz/p/10858982.html
Copyright © 2020-2023  润新知