模拟费用流是一个非常巧妙的算法,余之前也对其进行了许多研究,但一直没有触碰到它的本质:模拟费用流,自然就是在费用流的基础上模拟。
因此呐,这次余找到一道比较好也比较有难度的例题,来进行一次模拟费用流算法的巩固深化复习。
考虑暴力费用流,建图如下:
解释:一般的边对应选出一对下标相同的数的情况。由于能任选\(k-l\)对,因此任选边\(p\rightarrow p‘\)的流量是\(k-l\)。
然而直接跑费用流显然是无法通过此题的。
模拟费用流是对费用流的模拟,接下来的每种情况其实都在费用流的图中有着对应的流法(于括号中给出)。
考虑\(p\rightarrow p‘\)肯定是最优的边,因此先贪心将其流满。
具体地,对两个序列各自开一个堆,每次选出还未选择过的\(a\)中最大元素\(a_u\)和\(b\)中最大元素\(b_v\),将总流量\(k\)以及\(p\rightarrow p‘\)的容量减\(1\)。
(\(S\rightarrow S‘\rightarrow u\rightarrow p\rightarrow p‘\rightarrow v‘\rightarrow T\))
然而如果\(b_u\)或者\(a_v\)已经被选择过了,那么就可以让它们不流\(p\rightarrow p‘\)这条任选边,而是从一般的边上走,此时可以将\(p\rightarrow p‘\)的容量加\(1\)。
(\(S\rightarrow S‘\rightarrow u\rightarrow u‘\rightarrow T\)或\(S\rightarrow S‘\rightarrow v\rightarrow v‘\rightarrow T\))
流满了\(p\rightarrow p‘\),接下来有\(3\)种选择:
具体实现也就是开五个堆,分别存储剩余的最大的\(a_u\)、剩余的最大的\(b_v\)、最大的\(b_u\)已经被选过的\(a_u\)、最大的\(a_v\)已经被选过的\(b_v\)、都未选过的\(a_x,b_x\)。
至此,终于可以对模拟费用流算法进行一次总结了:
咳咳,这就是余目前能想到的有关模拟费用流的全部内容啦!
原文:https://www.cnblogs.com/Nero-Claudius/p/Simulation_of_CostFlow3.html