转载:http://www.cnblogs.com/onioncyc/p/6496532.html
【最大流】复杂度O(n^2*m)
网络流:http://m.blog.csdn.net/article/details?id=9401909
网络流本质上是为了解决一类取舍问题,这类取舍问题无法得知最优策略的模式(无法DP),因此通过构造一些带容量的路径表示原题目容量,模拟水流在这些容量之间的取舍,从而可以利用网络流来解决取舍问题。
当前弧优化是因为DFS过程中访问x点时一旦流入量=流出量就退出,所以可以记录下此时正在考虑的弧,下次从此处继续考虑即可。
当前弧之前的弧,不能使流入量-流出量=0,那么一定该弧以及该弧之后的弧中有断裂,那么下次再考虑就没有意义了。
当前弧本身,使流入量-流出量=0,也就是使该点前面的弧中最小的一条断裂了,当前弧以及当前弧连出去之后的弧只是有可能断裂,那么下次就应该从这条当前弧开始考虑。
当前弧优化的效果还是很不错的!
我的写法中直接用flow表示剩余流量,思路和程序结构参考紫书。
记得建反向弧,记得tot=1,不是0!也不是2!
edge开大!
不深究反向弧的意义的话,它就只是flow为0的配套弧,在整个网络流过程都和正常弧没区别。
反向弧的意义无非就是给程序反悔的机会,本来A-->B流了2单位的流,
此时另一路C增广到B时发现这条路的流可以代替一部分(或全部)B之前的流,而A就可以把被代替的这部分流从其他路径D流向终点。
在建了反向弧之后,上行这种发现就表现为C--B--A--D,即C到B后通过反向弧B-A流向D。
这种表现与描述似乎没有很大的相关性,确实等价的,这一切得益于反向弧的存在。
反向弧给程序提供了反悔的机会,本来A-->B流了2,此时发现别的路帮A流一些,而A省下来的流去其他路更好,要实现这种行为就流反向弧即可。
所以,流反向弧不会改变残量网络的总流量,因为这种行为只是在原来的流量中借一部分出来而已。残量网络留下一些反向弧完全没问题而且也是必要的。
1.tot=1
2.用d记层次
3.if(a==0)break
4.cur当前弧优化
5.二分图开双倍点
【费用流】
关于最小费用最大流算法,与黄学长模板类似。
但是,黄学长标的zkw并不对,按照那篇论文应该叫原始对偶 (Primal-Dual) 算法。
是一种保留spfa的同时改用多路增广的算法,不怕负权,怕负环。
e[i].flow只要走边都必须判断。
spfa 从T开始建立以cost为边权的最短路图,与普通spfa的只是从终点开始搜,边要反过来(e[i^1].cost)
dfs 从S开始多路增广寻找最大流,与dinic的不同:
dinic中走的路要求严格遵循层次图,因此不需要担心走回头路。
dfs中走的路要求遵循最短边(即该边在点x到点T的某条最短路上),因此要记录vis避免走回头路或成环。
还有dfs过程中累加ans=e[i].cost*f(可以保证流f不超容)。
关于费用流的用途:
最大流是让水流在通道内尽可能多的流到终点,为此需要填满所有S到T的通路才停止,从S到T的水流可能有多次分分合合。
而费用并不是简单的“第二关键字”,为许多不同的最大流方案加上代价,以寻找最有价值(代价最小)的流。
dfs自带多路增广,一遍就可以了,不用while。
1.加当前弧优化
2.加SLF优化(spfa)
3.dfs时要回溯
4.tot=1
5.边edge开大!
6.memset数个数,记得int类型*4!
7.spfa要从终点
8.费用流dfs时记得vis数组
<最小费用流>
流量不固定的s-t最小费用流。如果网络中的费用有正有负,如何求s-t最小费用流?注意,这里的流量并不固定。
解:如果费用都是正的,最小费用流显然是零流;但由于负费用的存在,最短增广路的权值可能是负的,这样增广之后会得到更小的费用;但随着增广的进行,增广路权值逐渐增大,最后变成正数,此时应该停止增广。换句话说,最小费用随着流量增大先减小,后增大,成下凸函数。前面说过,下凸函数求最小值一般使用三分法,但这里可不用这么麻烦,只需在最短增广路费用为正时停止增广即可,三分反而比较慢(想一想,为什么)。需要注意的是,如果一开始不仅有负费用弧,还有负费用圈,必须先用消圈法消去负圈,否则最短增广路算法的前提不成立。当然,如果网络是无环的,则无此问题。——刘汝佳《算法竞赛入门经典——训练指南》
流量不固定(不考虑最大流)的费用流:spfa最后返回时当且仅当最短路总费用对答案有贡献(如<0)时返回。
<负圈>费用流有负权时就要需要考虑负圈的问题:
原理是消圈定理:流量为f的流是最小费用流当且仅当不存在负费用增广圈。
消圈算法:如果在一个流网络中求出了一个最大流,但对于一条增广路上的某两个点之间有负权路,那么这个流一定不是最小费用最大流,因为我们可以让一部分流从这条最小费用路流过以减少费用,所以根据这个思想,可以先求出一个最大初始流,然后不断地通过负圈分流以减少费用,直到流网络中不存在负圈为止。关键在于负圈内所有边流量同时增加是不会改变总流量的,却会降低总费用。
原图中若存在负圈就必须先用消圈算法消除负圈,每次spfa找负圈后将圈内容量最小边满流(留下反向边)同时费用累加进答案,圈内其它边加上一样的流量,这样总流量是不会变化的但总费用变低,然后接着跑spfa直到没有负圈。
最常用的连续最短路(单路或多路)每次都贪心地取最小费用路径在增广,所以每次增广的都是最优的,不存在增广过程中产生负圈的可能,但要注意它无法处理图一开始就存在负圈的情况。
【有上下界网络流】
<无源汇上下界可行流>相当于重建图后跑最大流。
如果存在一个可行流,那么一定满足每条边的流量都大于等于流量的下限.因此我们可以令每条边的流量等于流量下限,得到一个初始流,然后建出这个流的残量网络:每条边的流量等于这条边的流量上限与流量下限之差(真正建图)。(不用真的建原反向边)
这个初始流不一定满足流量守恒,因此最终的可行流一定是在这个初始流的基础上增大了一些边的流量使得所有点满足流量守恒.
因此我们考虑在残量网络上求出一个另不满足流量守恒的附加流,使得这个附加流和我们的初始流合并之后满足流量守恒.即:
如果某个点在所有边流量等于下界的初始流中满足流量守恒,那么这个点在附加流中也满足流量守恒,
如果某个点在初始流中的流入量比流出量多x,那么这个点在附加流中的流出量比流入量多x.
如果某个点在初始流中的流入量比流出量少x,那么这个点在附加流中的流出量比流入量少x.
循环流只要求每个点流量守恒,这启发我们建立S、T来引流。(S、T只是引流的作用,如果本来只填下界就流量守恒那甚至不用跑最大流了。)
入度>出度时(in[x]>0)时,需要流出去,所以从源向点引一条容量in[x]的边,引诱它流出去。
因为源进来的流量不是真的流量,而出去的流量却是真的,如果平衡了,流出去的就相当于补足原来多的入度。
入度<出度时(in[x]<0)时,需要流进来,所以从点向汇引一条边,引诱它流进来。同上。
为何这样正确?源和汇的作用只是引诱,让入度多的点流向出度多的点,最终实现流量平衡。
由于源汇连出来容量相同(一入度对应一出度,多余量也一定相同),所以如果最终满流就实现了流量平衡,此时源汇就可以无视了。
所以如果最大流==S邻边流量上界之和说明存在可行流,流量为下界流量和(初始流)+最大流(附加流)
1.加边时记录每个点入度和出度(in[i])。
2.根据in[i]建源汇连新边。
最大流
3.检验源点出去的边是否满流。
<有源汇上下界可行流> 模板
要求一个流使得源点的总流出量等于汇点的总流入量,其他的点满足流量守恒,而且每条边的流量满足上界和下界限制。
S流不进,T流不出,S的流出量又和和T的流入量相等,这启发我们从t向s连一条容量inf的边,然后跟上面一样处理(建SS,TT)即可。
判断可行方法与上相同(判断最大流与S邻边),最终t-->s的反向边上存着可行流的总流量(不需要再加原来的下界流量)。
为什么不需要再加原来的下界流量?因为最初根据下界设置基准流量时,基准流量汇集为终点T的in[T]中(入度有余)。
而超级源SS正是把in[T]通过t-->s引向出度有余起点S,所以t-->s的反向边上存着基准流量。
在后来为了流量平衡的增广中,影响到总流量的增广一定会影响到T-->S这条边(很多边的增广只是互补,没有影响t-->s边就不会影响总流量)
从另一方面解释:总流量==S的总流出量==T的总流入量==T-S边的流量。
<有源汇上下界最大流>先和上面一样从t向s连边,然后跑可行流(建SS,TT),判断可行。
再以s、t在残量网络上跑最大流,该最大流就是最终答案!(不用做什么额外处理,因为额外边全部满流了)
要注意的是原循环流流量存在终点往起点的反向弧中了,最后跑最大流时自然会计算进去。
答案就是最后一次最大流。
会不会增广的时候使得一些边不满足流量下限?
不会。因为我们一开始建的就是把流量下限拿出去之后的图,而之后的操作(如最大流)都是符合流量平衡的,极端情况下就都等于流量下界而已(下界符合平衡时)。
<有源汇上下界最小流>先跑有源汇可行流,然后反向跑t-->s的最大流(增加反向边流量相当去减去正向边流量),答案是可行流-最大流。
<上下界最小费用最大流>先找原图的负圈消去,然后跑可行流(不会产生负圈),最后跑s-t/t-s最小费用最大流/最小费用流。
最小费用循环流:找图中的负费用增广圈增广,对于必须满流的边可以设cost为负无穷。
因为循环流没有最大流,若要在循环流中寻找极限值可以尝试附加费用。
【二分图】
一个无向图是二分图的充要条件是不存在奇环。
常用技巧:棋盘图黑白染色形成二分图&&网格x-y形成二分图。
S向左侧xi连边,右侧yi向T连边。
二分图题目先转化成对应二分图模型,再对应转化为网络流。
标准建图:边权全为1。
1.最大匹配=最大流(最大匹配就是匹配边数最大)
2.最小覆盖=最小割(最小覆盖就是选择最少的点使每条边至少有一个端点被选中,选点类比割边就是最小割)
3.最大独立集=总点数-最小覆盖(最大独立集就是选择最多的点使每条边至少有一个点不被选中。独立集中不能有边,每个两点匹配只能选一点,所以把最大匹配数减去后就是答案。)
4.最小路径覆盖:在DAG找尽量少的路径,使每个节点恰好在一条路径上(点不相交)。
做法:将每个点拆开分别放入xy集合中,如果u到v有一条边,则连边u,v`,然后二分图最大匹配。
初始未匹配ans=n即每个点单独为一条路径,匹配一条说明连了两点,ans-1,所以最终ans=N-最大匹配。
5.二分图带权匹配:要求完美匹配就跑费用流,不要求完美匹配就跑流量不固定的费用流(spfa时若最短路费用对答案没贡献就返回失败)。
【最小割】
最小割:割掉最少的边,使S无法到达T。
最大流最小割定理:
1.最小割等价于最大流。
2.最小割在最大流中一定是满流边,是增广路径中容量最小的边。
3.一条增广路径只对应一条最小割。(如果一条增广路中两条满流且都需要割掉,那一定通过反向边分成两条增广路)
以下是详解。
特性:一条路径必须选一条边(最小)隔断。
定义:把所有顶点分成两个集合S和T=V-S,其中源点s在集合S中,汇点t在集合T中。如果把“起点在S中,终点在T中”的边都删除,就无法从s到达t了,这样的集合划分(S,T)称为一个s-t割,它的容量是起点在S终点在T的所有边的容量和。当不存在增广路时(跑完最大流的残量网络中),S和T分离,跨越集合S和T的边都满载,组成最小割集。
最小割在最大流中一定是满流边,其实就是S到T之间必须经过的边(不管确定与否)。只要找到一条增广路径,就必须经过一条最小割。最小割中的边饱和就再也不能找到增广路径。
一条最小割可以对应多条增广路径,但是一条增广路径只能对应一条最小割(或最小割的可能性)。
求最小割其实就是一条增广路径中容量最小的边,这恰好与最大流的求解是一致的。
每条增广路出一条最小割,该最小割就是增广路中容量最小的边(集)(多条等大时就有多种可能),这条最小割就是把增广路隔断的罪魁祸首。
即使有多种可能,但是定出来的最小割都是必须经过的,实际上它们都是最小割,任意一条割掉都是一样的效果。
两点之间的边(一条或多条)要么同为最小割,要么同不为最小割。
简单求解:再得到最大流f后的残留网络fG中,从开始深度优先遍历(DFS),所有被遍历到的点,即构成点集。注意,虽然最小割中的边都是满流边,但满流边不一定都是最小割中的边。
详细求解:最小割集不是一定的,跑完最大流后缩点(跑一半的边因为反向弧全部被缩),
剩下的满流边(无视未流边)有些边一定是最小割(id[u]==id[S]&&id[T]==id[v]),有些边可能是最小割(id[u]!=id[v])
因为留在外面的边只能是满流边,所以一条S-T路径若包含多条边(边集,即每两个点之间所有边的和,不是重边),这多个边集一定是等大的,都可能是最小割。
实际上只有一条路径上有多个边集的容量等大时,最小割才是不确定的,否则最小割就是容量最小的那条边(集)。
未流边不可能是最小割,因为若该边能连通,其未流的原因必是u->v被其它边(一条或多条)流了,那么最小割就一定是该路径中限制了流量的边,若它自己是最小割就不会被别的边限制流量了。
半流边不可能是最小割,因为限制了流量的边显然不是它。
【最大权闭合子图】
S向正权点连边,负权点向T连边,0不管,原边全部转为正无穷(节点权值全部转到了与S、T的连边上)。
注意:上文中后面证明中的S集是闭合子图和源点S的集合,T集是其它点和汇点T的集合!
割掉与S相邻的边就是这个点舍弃了S,成为T中的正权点(离开闭合子图);割掉与T相邻的边就是这个点舍弃T,成为S中的负权点(进入闭合子图)。(割的值与答案密切相关)
因为每条路径必须有割,所以对于所有依赖关系要么与T相邻断边(把依赖对象收进来),要么与S相邻断边(把依赖源扔掉)。
最大权闭合子图的权值=所有正权点之和-最小割
可以简单理解为理想可以收入所有正权点,舍弃所有负权点,然而实际上需要扔些正权点,捡一些负权点(即每条路径有一割)。
对于扔掉的正权点,就是减去割去的S邻边权值;对于捡起来的负权点,其实就是加上负权=减去割去的T邻边的权值。
所以权值=正权点之和-割,最小割对应最大权闭合子图。
【最大费用。。。】
1927: [Sdoi2010]星际竞速 最小权路径覆盖
bzoj 3876 支线剧情
PoPoQQQ 网络流 费用流 对偶图
3961: [WF2011]Chips Challenge
2055: 80人环游世界
最小费用循环流(紫书) BZOJ2673: [Wf2011]Chips Challenge 网络流+费用流
紫书例题 网络流24题
最小割 k覆盖 密度子图 上下界
费用-优先级 循环 流X费√
bzoj 3550 线性规划与网络流
分治维护决策单调性
最大权闭合(子)图 最大权闭合图 hiho 第119周 最大权闭合子图
【网络流技巧】
1.弧cost=a*(flow)^2。
拆边,cap=5时拆成5条边cost=1a,3a,5a,7a,9a。
源于数学理论x^2=1+3+5+...2*x-1(一个数的平方可以表示为连续奇数之和)
【稳定婚姻】
每个尚未订婚的男士在他没有求过婚的女士中选一个最喜欢的求婚,然后女士选择向她求婚的最喜欢的一个(包括原未婚夫)订婚。
开始将所有男士入队,然后每次匹配后失配的男士再次从尾端进入队列。
男士优先选择喜欢的结果就是男士最优、女士最差的搭配,反之。
【题目】
1.【CODEVS】1993 草地排水 最大流
2.【BZOJ】1066: [SCOI2007]蜥蜴 最大流
3.【CODEVS】1034 家园 最大流
4.【费用流】【CODEVS】1227 方格取数2 最小费用最大流(费用流)
5.【CODEVS】1033 蚯蚓的游戏问题 最小费用最大流(费用流)
6.【BZOJ】1834 [ZJOI2010]network 网络扩容 最大流+最小费用最大流(费用流)
最小割模型在信息学竞赛中的应用(ppt) NOI最大获利
7.【CODEVS】1022 覆盖 二分图最大匹配
题意:n*m图中有若干水塘(1*1不能覆盖),求最多能用多少1*2的矩阵区覆盖(不能重叠)。
题解:对i+j进行奇偶染色,就可以保证相邻两格异色,然后就是二分图最大匹配了。
8.【CODEVS】1922 骑士共存问题 最大独立集
9.网络流24题之最小路径覆盖问题 最小路径覆盖
10.【网络流24题】魔术球问题 最小路径覆盖
11.【BZOJ】1070 [SCOI2007]修车 最小费用最大流(费用流)
12.【有上下界网络流】【ZOJ】2314 Reactor Cooling 有上下界网络流(最大流)