• 网络流基础


    前言:

    关于网络流,按董大佬的话,就是个板子,会打也没用

    正文:

    最大流

    最大流的基础求法就是増广路算法($EK$)

    虽然它跑的慢,但也要会打,因为可以魔改求费用流

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using std::queue;
    const int maxn=11111;
    #define inf (0x3f3f3f3f)
    
    class Max_Flow
    {
        private:
            
            struct edge
            {
                int to,next,cap;
                edge(){}
                edge(int to,int next,int cap):to(to),next(next),cap(cap){}
            };
            
            edge e[maxn*20];
            int cnt,head[maxn];
    
            void add(int from,int to,int cap)
            {
                e[++cnt]=edge(to,head[from],cap);
                head[from]=cnt;
            }
    
            struct node
            {
                int pre,kth;
            };
            
            node p[maxn];
            bool vis[maxn];
        
            bool bfs(int s,int t)
            {
                memset(p,0,sizeof(p));
                memset(vis,0,sizeof(vis));
                queue<int>q;
                q.push(s);
                p[s].pre=s;
                vis[s]=1;
                while(!q.empty())
                {
                    int u=q.front(); q.pop();
                    for(int i=head[u];i!=-1;i=e[i].next)
                    {
                        int v=e[i].to;
                        if(!vis[v]&&e[i].cap)
                        {
                            vis[v]=1;
                            p[v].pre=u;
                            p[v].kth=i;
                            if(v==t) return 1;
                            q.push(v);
                        }
                    }
                } 
                return 0;
            }
            
        public:
    
            Max_Flow()
            {
                cnt=-1;
                memset(head,-1,sizeof(head));
            }
            
            void addedge(int u,int v,int w)
            {
                add(u,v,w);
                add(v,u,0);
            }
            
            int EK(int s,int t)
            {
                int maxflow=0;
                while(bfs(s,t))
                {
                    int minn=inf;
                    for(int i=t;i!=s;i=p[i].pre)
                        minn=std::min(minn,e[p[i].kth].cap);
                    for(int i=t;i!=s;i=p[i].pre)
                    {
                        e[p[i].kth].cap-=minn;
                        e[p[i].kth^1].cap+=minn;
                    }
                    maxflow+=minn;
                }
                return maxflow; 
            }
    }flow;
    
    int main()
    {
        int n,m,s,t;
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,u,v,w;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            flow.addedge(u,v,w);
        }
        printf("%d
    ",flow.EK(s,t));
        return 0;
    }

    当然 $EK$ 的效率显然无法满足我们的要求

    所以我们要进行优化,先将图进行分层,再去増广

    于是我们有了 $Dinic$ 算法,还有基于它的各种鬼畜优化

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using std::queue;
    const int maxn=11111;
    #define inf (0x3f3f3f3f)
    
    class Max_Flow
    {
    
        private:
    
            struct edge
            {
                int to,next,cap;
                edge(){}
                edge(int to,int next,int cap):to(to),next(next),cap(cap){}
            };
    
            edge e[maxn*20];
            int cnt,head[maxn];
    
            void add(int from,int to,int cap)
            {
                e[++cnt]=edge(to,head[from],cap);
                head[from]=cnt;
            }
    
            int deep[maxn];
    
            bool bfs(int s,int t)
            {
                memset(deep,0,sizeof(deep));
                queue<int>q;
                q.push(s);
                deep[s]=1;
                while(!q.empty())
                {
                    int u=q.front(); q.pop();
                    for(int i=head[u];i!=-1;i=e[i].next)
                    {
                        int v=e[i].to;
                        if(!deep[v]&&e[i].cap)
                        {
                            deep[v]=deep[u]+1;
                            if(v==t) return 1;
                            q.push(v);
                        }
                    }
                }
                return 0;
            }
    
            int dfs(int u,int limit,int t)
            {
                if(u==t||!limit) return limit;
                int sum=0;
                for(int i=head[u];i!=-1;i=e[i].next)
                {
                    int v=e[i].to;//关于当前弧优化,我并不会
                    if(deep[v]==deep[u]+1&&e[i].cap)
                    {
                        int flow=dfs(v,std::min(limit-sum,e[i].cap),t);
                        if(!flow) deep[v]=0;//据说叫炸点优化,感觉好霸气的样子
                        sum+=flow;
                        e[i].cap-=flow;
                        e[i^1].cap+=flow;
                        if(sum==limit) break;//这句剪枝一定要加上,否则会慢很多
                    }
                }
                return sum;
            }
    
        public:
    
            Max_Flow()
            {
                cnt=-1;
                memset(head,-1,sizeof(head));
            }
    
            void addedge(int u,int v,int c)
            {
                add(u,v,c);
                add(v,u,0);
            }
    
            int Dinic(int s,int t)
            {
                int maxflow=0;
                while(bfs(s,t))
                {
                    maxflow+=dfs(s,inf,t);
                }
                return maxflow;
            }
    
    }flow;
    
    int main()
    {
        int n,m,s,t;
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,u,v,c;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&c);
            flow.addedge(u,v,c);
        }
        printf("%d
    ",flow.Dinic(s,t));
        return 0;
    }

    费用流

    关于费用流,就是将 $EK$ 的 $bfs$ 魔改为 $spfa$ ,每次増广出一条最短路

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using std::queue;
    const int maxn=5555;
    #define inf (0x3f3f3f3f)
    
    class Mincost_Maxflow
    {
        
        private:
            
            struct edge
            {
                int to,next,cap,dis;
                edge(){}
                edge(int to,int next,int cap,int dis):to(to),next(next),cap(cap),dis(dis){}
            };
            
            edge e[maxn*20];
            int cnt,head[maxn];
            
            void add(int from,int to,int cap,int dis)
            {
                e[++cnt]=edge(to,head[from],cap,dis);
                head[from]=cnt;
            }
            
            struct node
            {
                int pre,kth;
            };
            
            node p[maxn];
            int dis[maxn];
            bool vis[maxn];
            
            bool spfa(int s,int t)
            {
                memset(p,0,sizeof(p));
                memset(vis,0,sizeof(vis));
                memset(dis,inf,sizeof(dis));
                queue<int>q;
                q.push(s);
                p[s].pre=s;
                dis[s]=0,vis[s]=1;
                while(!q.empty())
                {
                    int u=q.front(); q.pop(); vis[u]=0;
                    for(int i=head[u];i!=-1;i=e[i].next)
                    {
                        int v=e[i].to;
                        if(dis[v]>dis[u]+e[i].dis&&e[i].cap)
                        {
                            dis[v]=dis[u]+e[i].dis;
                            p[v].pre=u;
                            p[v].kth=i;
                            if(!vis[v])
                            {
                                q.push(v);
                                vis[v]=1;
                            }
                        }
                    }
                }
                return p[t].pre;
            }
        
        public:
            
            int mincost,maxflow;
            
            Mincost_Maxflow()
            {
                cnt=-1;
                memset(head,-1,sizeof(head));
            }
            
            void addedge(int u,int v,int c,int w)
            {
                add(u,v,c,w);
                add(v,u,0,-w);
            }
            
            void mincost_maxflow(int s,int t)
            {
                while(spfa(s,t))
                {
                    int minn=inf;
                    for(int i=t;i!=s;i=p[i].pre)
                        minn=std::min(minn,e[p[i].kth].cap);
                    for(int i=t;i!=s;i=p[i].pre)
                    {
                        e[p[i].kth].cap-=minn;
                        e[p[i].kth^1].cap+=minn;
                    }
                    maxflow+=minn;
                    mincost+=minn*dis[t];
                }
            }
            
    }flow;
    
    int main()
    {
        int n,m,s,t;
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1,u,v,c,w;i<=m;i++)
        {
            scanf("%d%d%d%d",&u,&v,&c,&w);
            flow.addedge(u,v,c,w);
        }
        flow.mincost_maxflow(s,t);
        printf("%d %d
    ",flow.maxflow,flow.mincost);
        return 0;
    }

    后序:

    关于最大流的 $ISAP$ 算法和 $HLPP$ 预流推进以及 $zkw$ 费用流

    因为我太菜了,所以都没学,想学的话可以私聊这位大佬 

  • 相关阅读:
    PyTorch之前向传播函数自动调用forward
    pytorch 调用forward 的具体流程
    Xcode5下使用纯代码构建简单的HelloWorld程序
    浅谈iOS 5的StoryBoard
    iOS单例
    instancetype 对比 id 的好处
    JSP的7个动作指令
    IOS UIView子类UIScrollView
    XCODE4.6从零开始添加视图
    NSSet类型 以及与NSArray区别
  • 原文地址:https://www.cnblogs.com/Vscoder/p/10530242.html
Copyright © 2020-2023  润新知