Loading

模拟费用流入门

基本思想

首先建出网络流模型,然后通过一些手段快速模拟增广过程:

  1. 寻找增广路:观察图的结构,使用 选取关键点、数据结构维护 等方法快速求出增广路。
  2. 增广与退流:将得到的增广路统计进答案,维护残量网络。

网络流算法之所以能够简单方便地解决贪心问题,正是因为有 “退流” 的存在。
退流相当于贪心中的 “反悔” 操作,这使得我们不需要在意加入增广路的顺序。

为方便阅读,以下给出的网络流建模图,对于相同类型的边只标一次流量/花费。

关键点法

AGC018C Coins

上图的意思是先钦定所有点都为金,流到 \(U\) 则改为银,流到 \(V\) 则改为铜。

可以看出上图存在四个关键点:\(S,U,V,T\)
为了快速寻找增广路,我们尝试只对这四个点建图,那么新图中某两个点之间可能的边即为原图中所有不经过其他关键点的路径。使用堆维护所有这样的路径:

  • \(S\to U: b_i-a_i\),要求 \(i\) 未选过。
  • \(S\to V: c_i-a_i\),要求 \(i\) 未选过。
  • \(U\to V: -(b_i-a_i)+(c_i-a_i)=c_i-b_i\),要求 \(i\) 此前流向 \(U\)
  • \(V\to U: -(c_i-a_i)+(b_i-a_i)=b_i-c_i\),要求 \(i\) 此前流向 \(V\)

那么为了求 \(S\to T\) 的最长路,我们讨论所有可能的路径:

  • \(S\to U\to T\)
  • \(S\to V\to T\)
  • \(S\to U\to V\to T\)
  • \(S\to V\to U\to T\)

找出最长路后进行增广与退流,也即根据残量网络变化情况维护四个堆。

由于每次增广都会使流量加一,而最大流是 \(Y+Z\),故总复杂度 \(O(n\log n)\)

https://atcoder.jp/contests/agc018/submissions/68587065

NOI2019D1T3 序列

上图中 \(U\to V\) 表示选了多少对不同下标,\(A_i\to B_i\) 则表示选了这对相同下标。
值得一提的是,这题直接跑费用流即可获得高达 64 分,可见难点其实在于建出上面这张图()

类似上一道题的做法,我们选取 \(S,U,V,T\) 为关键点,维护关键点之间的边:

  • \(S\to U: a_i\),要求 \(A_i\) 未选过。
  • \(S\to V: a_i\),要求 \(A_i\) 未选过,且已存在 \(V\to B_i\) 的流。
  • \(U\to T: b_i\),要求 \(B_i\) 未选过,且已存在 \(A_i\to U\) 的流。
  • \(V\to T: b_i\),要求 \(B_i\) 未选过。
  • \(S\to T: a_i+b_i\),要求 \(A_i,B_i\) 均未选过。

细心的读者可以发现 \(U,V\) 之间的路径不止 \(U\leftrightarrow V\) 一种,还存在以下情况:

  • \(U\to A_i\to B_i\to V\)
  • \(V\to B_i\to A_i\to U\)

但是如果我们考虑这样的路径,那么增广路可以形如 \(S\to U\to V\to U\cdots\to T\),长度可以达到 \(O(n)\),这显然不能接受。

考察这两种路径存在的条件,发现需要存在 \(i\) 使得 \(A_i\to U,V\to B_i\),这与两个虚点的意义不符。那么如果我们能避免出现这样的流,就可以不管这两种路径了。
如何做到呢?其实只需要将边 \((U,V)\) 的花费改为 \(-\varepsilon\),这样 \(A_i\to U,V\to B_i\) 的贡献就不如 \(A_i\to B_i\),自然就不会往虚点流了。
在实现上可以不显式地考虑这个 \(\varepsilon\),只需微调几种路径的考虑顺序即可。这也就是洛谷讨论区所谓 “优先级” 的问题来源。

回到做法的叙述。所有可能的路径如下:

  • \(S\to T\)
  • \(S\to U\to T\)
  • \(S\to V\to T\)
  • \(S\to U\to V\to T\)
  • \(S\to V\to U\to T\)

与上一道题相似地维护即可。时间复杂度 \(O(n\log n)\)

https://loj.ac/s/2403180

特殊图

posted @ 2025-08-17 15:10  Accelessar  阅读(71)  评论(0)    收藏  举报