网络流之最大流
Posted gmsd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流之最大流相关的知识,希望对你有一定的参考价值。
暑假就已经学过了,可是因为我太菜了,所以完全没懂,今天老师要我们落实之前学的,就复习了网络流
虽然CSP不考,但是学了也可以用(就像去年D2T3,动态DP模板)
好了,接下来进入正题:
首先,啥子事网络流,官方解释如下
在图论中,网络流(英语:Network flow)是指在一个每条边都有容量(capacity)的有向图分配流,使一条边的流量不会超过它的容量。
通常在运筹学中,有向图称为网络。顶点称为节点(node)而边称为弧(arc)。一道流必须匹配一个结点的进出的流量相同的限制,除非这是一个源点(source)──有较多向外的流,
或是一个汇点(sink)──有较多向内的流。一个网络可以用来模拟道路系统的交通量、管中的液体、电路中的电流或类似一些东西在一个结点的网络中游动的任何事物。
嘿嘿,好像不懂,简单一点来说:
有一个储水站,给一个小区分配水,而你又住在里面
每家每户都有不同规格的水管,也就是说,在速度不变的情况下,同一时间内,流动的水的多少不同
而且从储水站里面送出来的速度必须一样,因为流速越快,液体压强越大
我们当然不希望水管炸裂
每一户人家用完的水肯定要运输到一个废水处理站
我们需要求的是储水站最多可以送出多少水,最后能够送到废水处理站(因为要回收利用)
我第一次看到这个题目时,产生了一段对话:
我:这个不就是暴力枚举吗???
某巨佬:......这个超时了
我:......那怎么做
某巨佬:EK或者是Dinic
我:???什么玩意儿
首先明确几个概念:
容量:每条边都有一个容量(水管的最大水流容量)
源点:出发点(储水站)。
汇点:结束点(废水处理站)。
流:一个合法解称作一个流,也就是一条可以从源点到汇点的一条合法路径。
流量:每条边各自被经过的次数称作其流量,最终收集的总数为整个流的流量。
增广路:在当前网络之后找到一条能够从源点到汇点能运更多货物的路径。当一条边被增广之后(即它是增广路的一部分,或者说增广路通过这条边),这条边还能通过的流量,叫做剩余流量,修改之后的图称为残量网络。
首先是我最喜欢的EK算法(主要是代码易懂,简洁,适合我这种蒟蒻)
它的思想很简单,每一次疯狂的寻找增广路,当然如果其中有一条边为‘0’,就不是增广路,将当前的流量减去中间的最小值(肯定的,因为如果不是最小值水就不能通过)
ans加上当前这个最小值,直到寻找不到增广路
但是有瑕疵,可以把这个hack掉:
我们可以轻易知道,答案为2,但是如果按照以上思想:
程序会这样跑,以至于ans=1:
所以,我们需要给这个程序一个后悔的机会
是不是想到dfs回溯,很明显,超时了
所以我们想到了一个巧妙的办法,建反边,初始值为零
在找增广路的时候,设这条路的最小流量为opt
那么,反边的值+opt,正边-opt
我们可以这么想,我们走反的边相当于将水退了回去
好的,就这样,AC代码如下:
#include<bits/stdc++.h> using namespace std; const int N=300002; int spot,EDGE,S,E; int head[N],ver[N],nxt[N],tot,edge[N]; int q[N],hd,tl,res[N],now[N],pre[N],ans; int read() int s=0,w=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘)w=(ch==‘-‘)?-1:1,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)s=s*10+ch-‘0‘,ch=getchar(); return s*w; void write(int x) if(x<0) putchar(‘-‘);x=-x; int y=10,len=1; while(y<=x) y*=10;len++; while(len--)y/=10;putchar(x/y+48);x%=y; void add(int x,int y,int z) ver[++tot]=y;edge[tot]=z;nxt[tot]=head[x];head[x]=tot; bool Bfs() memset(res,0,sizeof(res)); hd=0;tl=1;q[1]=S;res[S]=1;now[S]=1e9; while(hd^tl) hd++; int x=q[hd]; for(int i=head[x];i;i=nxt[i]) int y=ver[i]; if(!res[y]&&edge[i]>0) now[y]=min(now[x],edge[i]);pre[y]=i; if(y==E)return 1; tl++;q[tl]=y;res[y]=1; return 0; void EK() ans+=now[E]; int x=E; while(x!=S) edge[pre[x]]-=now[E];edge[pre[x]+1]+=now[E]; x=ver[pre[x]+1]; int main() EDGE=read();S=1;E=read(); for(int i=1;i<=EDGE;i++) int x=read(),y=read(),z=read(); add(x,y,z);add(y,x,0); while(Bfs())EK(); write(ans); return 0;
// 10-2 //
以上是关于网络流之最大流的主要内容,如果未能解决你的问题,请参考以下文章
C#流总结(文件流内存流网络流BufferedStreamStreamReader/StreamWriterTextReader/TextWriter)
C#流总结(文件流内存流网络流BufferedStreamStreamReader/StreamWriterTextReader/TextWriter)