首页 > 技术文章 > 模拟费用流

yuanquming 2019-11-08 08:35 原文

参考资料:
https://www.mina.moe/archives/11762
https://blog.csdn.net/litble/article/details/88410435

sb typora怎么出bug了,写了一半全没了

鉴于某些原因来学一下模拟费用流

\(Case1\)

数轴上有若干兔子和洞,每只兔子必须进洞,一个洞只能进一只兔子,兔子只能往左边走,最小化所有兔子移动距离之和

这个问题我们可以这样考虑,平面上有一条折线,经过一个洞可以不变或往上,经过一个兔子必须往下,折线不能低于\(x\)轴,且最终高度必须为\(0\),最小化折线下方面积

那么我们发现只要让折线尽量不上升即可,而遇到一只兔子时意味着折线必须在直线的某个位置上升,贪心选取最右的即可,一遍sort+栈即可

\(Case2\)

数轴上有若干兔子和洞,每只兔子必须进洞,一个洞只能进一只兔子,洞有附加权值,兔子只能往左边走,最小化所有兔子移动距离与附加权值之和

我们尝试推广上一个模型,可以考虑给折线的每次上升和下降赋值,记坐标为\(x_i\),附加权值为\(w_i\),上升权值为\(w_i-x_i\),下降权值为\(x_i\),用一个可以动态维护最小值的数据结构就可以了

\(Case3\)

数轴上有若干兔子和洞,每只兔子必须进洞,一个洞只能进一只兔子,洞有附加权值,兔子可以往两边走,最小化所有兔子移动距离与附加权值之和

这里就有点麻烦了,因为会有后效性,如果我们把它看成一个最小权匹配,对应到费用流中,就是我们可能需要在某些时候退流

假设我们通过某种方法得到了一只兔子的权值为\(w_i\),通过某种方法得到了一个洞的权值为\(v_i\),兔子的坐标是\(x_i\),洞的坐标是\(y_i\),附加权值为\(s_i\),并从左往右依次考虑

如果一只兔子\(a\)匹配上了一个洞\(b\)

  • 总权值增加了\(x_a+v_b\)

  • 如果之后某一只兔子\(c\)抢走了这个洞,由于我们认为一开始每个兔子都匹配这一个权值\(inf\)的洞,那么\(b\)\(c\)抢走之后权值要加上\(x_c-x_a+inf\),可以认为是多了一个权值\(-x_a+inf\)的洞,由于权值是\(inf\)所以可以不加

  • 如果之后某一个洞\(c\)抢走了兔子\(a\),那么权值的变化为\(y_c+s_c-v_b-2x_a\),可以认为是多了一个权值\(-v_b-2x_a\)的兔子

如果一个洞\(a\)匹配上了一只兔子\(b\)

  • 总权值增加了\(y_b+s_b-w_a\)

  • 如果之后某个兔子\(c\)抢走了洞\(a\),由于我们认为\(b\)已经和他前面的某一个匹配了(这个匹配有可能是\(inf\),由于选择\(inf\)肯定不优所以我们贪心中一定会避免这种情况),所以对\(b\)来说这个洞被抢走他可以回去找之前的洞(类似于费用流中一条增广路的变化),而总权值要加上\(x_c-w_a-2y_b\),可以认为增加了一个权值\(-w_a-2y_b\)的洞

  • 如果之后某个洞\(c\)抢走了兔子\(b\),总权值要加上\(y_c+w_c-y_b-s_b\),那么可以认为新增了一只权值为\(-y_b-s_b\)的兔子

这样,兔子不再是兔子,洞也不再是洞,但是我们只需要两个堆就可以把它们处理的服服帖帖的

\(Case5\)

在#4的基础上,兔子和洞可以有分身(即一个点上可以有多个洞或兔子,数量$10^9$),求最小代价

在#4的基础上,记录权值的同时记录一下数量,对于一大批相同的洞,批量完成匹配和退流操作,还是用两个堆去维护

可以证明新建的节点数不会超过销毁节点数的\(c\)倍,其中\(c\)是某个常数,用势能分析可知总复杂度是\(O(cn\log cn)\)(我反正是不会证)

\(Case6\)

把#5的问题转化到树上

在树上我们只能自底向上合并子树中的兔子和洞,用可并堆维护即可。注意我们一开始需要为每只兔子分配一个权值\(inf\)的洞,这个洞是不能被别的兔子抢走的,否则这只兔子就真的无家可归了

推荐阅读