#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/45242511");
}
最终的最大流需要是一个循环体,流量在内部循环流动。
首先设每条边上界为flow,下界为low,那么就存在low的必须流和flow-low的自由流。
记录每个点的所有流入的必须流in和所有流出的必须流out。
然后新图先设立一个超级源点和一个超级汇点,
对于每条边,保留其自由流的容量,
对于每个点,若in-out<0,点到汇点连out-in的容量,反之源点到点连in-out的容量。
然后跑最大流,如果源点满流则可行。
首先对于一张固定了每条边最终使用容量的图,其最大流是可以将其拆分成的流量为1的环的数量。
如果按照常规方法在建立超级源汇以后跑完的残量网络上跑的话,可能只能枚举有剩余流量的点作为单次源点,这样我们无法保证每次的增广都使得答案更优。目前网上应该没有相关方法,蒟蒻我在浪费了若干脑细胞后证明了我这样弱的人并不能脑补出做法。
我们可以从汇点连一条下界为0,上界为inf的边到源点,这样就转化成了「无源汇」有上下界的「可行」流。
我们先跑一遍「有源汇」有上下界的「可行」流,得到最大流为maxflow1,然后在残量网络上删去新源和新汇,再做一遍裸最大流,得到最大流为maxflow2,则最终答案为maxflow1+maxflow2。
直接转化求可行流时超级源流量和。
反例:(边格式为起点,终点,下界,上界)
S:1, T:4
1 2 10 100
2 1 1 100
1 3 10 100
3 1 1 100
3 4 1 100
可行流答案为17,可是最小流是1。
因为可以循环计流使同一个流量在某条边上流多次。
一、
记录每个点的所有流入的必须流in和所有流出的必须流out。
然后新图先设立一个超级源点和一个超级汇点,
对于每条边,保留其自由流的容量,
对于每个点,若in-out<0,点到汇点连out-in的容量,反之源点到点连in-out的容量。
(完全由“「无源汇」有上下界的「可行」流”部分复制过来)
二、
超级源到超级汇跑最大流,然后在残余网络上从汇到源连一条容量为inf的边
三、
此时超级源到超级汇的最大流就是原图源到汇的最小流。
我们做特殊处理,就是把每条边(费用k)拆成必须流(流量a,费用k-inf)和自由流(流量b,费用k)两条边,
然后最后答案加上∑a*inf就好了。(注意此处inf不是真的极大值,而是赋一个很大的数就好)
费用小成这样必须选,然后选完了肯定会亏费用,要补回来。
原文地址:http://blog.csdn.net/vmurder/article/details/45242511