码迷,mamicode.com
首页 > 其他好文 > 详细

网络流基础

时间:2019-03-14 14:57:52      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:nbsp   turn   int   ora   dinic   node   cst   无法   main   

前言:

关于网络流,按董大佬的话,就是个板子,背下来就好了

正文:

最大流

最大流的基础求法就是増广路算法($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\n",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\n",flow.Dinic(s,t));
    return 0;
}

 还有一种 $ISAP$

网络流基础

标签:nbsp   turn   int   ora   dinic   node   cst   无法   main   

原文地址:https://www.cnblogs.com/Vscoder/p/10530242.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!