zoukankan      html  css  js  c++  java
  • 网络流学习(最大流)

    网络流学习

    入门

    Tank_long讲的知识点(概念)很有价值
    这哥们讲的也不错
    谢谢cwen提供的题目和知识要点

    嗯,我的代码还是很不错的

    题目:luogu模板网络最大流

    EK算法

    //EK算法:模板来自yyb
    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iomanip>
    #include<algorithm>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<vector>
    #define rg register
    #define il inline
    #define lst long long
    #define ldb long double
    #define N 10050
    #define M 100050
    using namespace std;
    const int Inf=1e9;
    il int read()
    {
    	rg int s=0,m=0;rg char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')m=1;ch=getchar();}
    	while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    	return m?-s:s;
    }
    
    int n,m,S,T,ans;
    int hd[N],cnt=1;
    int flow[N],pre[M];
    queue<int> Q;
    struct EDGE{int u,v,nxt,w,c,fb;}ljl[M<<1];
                          //流量,容量,反边编号
    il void add(rg int p,rg int q,rg int o)
    {
    	ljl[cnt]=(EDGE){p,q,hd[p],0,o,cnt+1},hd[p]=cnt++;//正向连边
    	ljl[cnt]=(EDGE){q,p,hd[q],0,0,cnt-1},hd[q]=cnt++;//连反边
    }
    
    int main()
    {
    	freopen("s.in","r",stdin);
    	n=read(),m=read(),S=read(),T=read();
    	for(rg int i=1;i<=m;++i)
    	{
    		rg int p=read(),q=read(),o=read();
    		add(p,q,o);
    	}
    	while(233)//疯狂增广路
    	{
    		for(rg int i=1;i<=n;++i)flow[i]=0;
    		while(!Q.empty())Q.pop();
    		Q.push(S),pre[S]=0,flow[S]=Inf;//从源点开始增广
    		while(!Q.empty())
    		{
    			rg int now=Q.front();Q.pop();
    			for(rg int i=hd[now];i;i=ljl[i].nxt)
    			{
    				rg int qw=ljl[i].v;
    				if(!flow[qw]&&ljl[i].c>ljl[i].w)
    				{
    					flow[qw]=min(flow[now],ljl[i].c-ljl[i].w);//更新flow,路上的最小值
    					pre[qw]=i;//储存此点的增广由来
    					Q.push(qw);
    				}
    			}
    			if(flow[T])break;//增广完了就没必要继续
    		}
    		if(!flow[T])break;//不能增广就退出
    		for(rg int now=T;now!=S;now=ljl[pre[now]].u)
    		{
    			ljl[pre[now]].w+=flow[T];//正边流量增多
    			ljl[ljl[pre[now]].fb].w-=flow[T];//方便后悔,反边流量减少(感性理解一下……)
    		}
    		ans+=flow[T];//统计答案
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    Dinic算法

    //Dinic算法:模板来自yyb
    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iomanip>
    #include<algorithm>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<vector>
    #define rg register
    #define il inline
    #define lst long long
    #define ldb long double
    #define N 10050
    #define M 100050
    using namespace std;
    const int Inf=1e9;
    il int read()
    {
        rg int s=0,m=0;rg char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')m=1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
        return m?-s:s;
    }
    
    int n,m,S,T;
    int hd[N],cnt=1;
    int dep[N];
    queue<int> Q;
    struct EDGE{int to,nxt,c,fb;}ljl[M<<1];
    il void add(rg int p,rg int q,rg int o)
    {
        ljl[cnt]=(EDGE){q,hd[p],o,cnt+1},hd[p]=cnt++;//存边
        ljl[cnt]=(EDGE){p,hd[q],0,cnt-1},hd[q]=cnt++;//反边
    }
    
    il bool BFS()
    //bfs找增广路,记录一个深度dep[]用于分层,有利于找到之后dfs
    {
        for(rg int i=1;i<=n;++i)dep[i]=0;
        while(!Q.empty())Q.pop();
        Q.push(S),dep[S]=1;//从S开始增广
        while(!Q.empty())
        {
            rg int now=Q.front();Q.pop();
            for(rg int i=hd[now];i;i=ljl[i].nxt)
            {
                rg int qw=ljl[i].to;
                if(ljl[i].c&&!dep[qw])//还有容量&&没增广到
                {
                    dep[qw]=dep[now]+1;//分层增广
                    Q.push(qw);
                }
            }
        }
        return dep[T];
    }
    
    int dfs(rg int now,rg int aim,rg int flow)
    {
        if(now==aim||(!flow))return flow;//到达终点||没有流量了 就不用增广了
        rg int res=0;
        for(rg int i=hd[now];i;i=ljl[i].nxt)
        {
            rg int qw=ljl[i].to;
            if(ljl[i].c&&dep[qw]==dep[now]+1)//有流量&&深度刚好 符合条件去增广
            {
                rg int kk=dfs(qw,aim,min(flow,ljl[i].c));
                res+=kk,flow-=kk;//局部最大流增加,可用流量减少
                ljl[i].c-=kk,ljl[ljl[i].fb].c+=kk;//正边减少容量,反边增加容量……
            }
        }
        return res;
    }
    
    il int Dinic()
    {
        rg int ans=0;
        while(BFS())//可以增广就一直增广
            ans+=dfs(S,T,Inf);//统计答案……
        return ans;
    }
    
    int main()
    {
        n=read(),m=read(),S=read(),T=read();
        for(rg int i=1;i<=m;++i)
        {
            rg int p=read(),q=read(),o=read();
            add(p,q,o);
        }
        printf("%d
    ",Dinic());
        return 0;
    }
    
  • 相关阅读:
    相由心生
    超级唯美的爱情语句(中英)
    有多少人败给“对不起,家里不同意”
    请善待老公,其实男人不容易
    摩托车西藏之旅实战攻略
    女人眼里36种不靠谱男人
    什么是爱?什么是幸福?
    踏板车的节油措施汇总
    史上最无语最蛋疼新闻标题
    太他妈幽默了,丫不去写书真浪费了
  • 原文地址:https://www.cnblogs.com/cjoierljl/p/9398523.html
Copyright © 2011-2022 走看看