网络流学习(最大流)

网络流学习

入门

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\n",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\n",Dinic());
    return 0;
}
posted @ 2018-07-31 21:58  Eternal风度  阅读(329)  评论(0编辑  收藏  举报
/*自定义地址栏logo*/