费用流

\(\color{#FDF5E6}{简单}\)费用流

相信大家都听懂了前天pa讲的课和昨天lyc讲的课,所以今天就可以划水

对于一条边 \([flow,v]\) 前者表示容量,后者表示费用。(当然有的时候他会变成表示上下界的自行辨别一下就好

废话连篇

放张图来当个封面遮一遮题解

直接应用

不经质疑(这真的是直接应用吗/泪奔

数字匹配

传送门

它是个费用流题,但是网络流都是单向的,这个匹配不是双向的吗

二分图匹配?这好像不是个二分图啊,来想想能不能把它分成两种,保证只有两种间能匹配,一种之内不能匹配。

匹配的条件是 \(a_i=a_j*p\) ,恰好多了一个质数因子,所以两者所含的质数因子总数奇偶行一定不同,奇数放左边,偶数放右边。

对于收益非负,每次找一条增广路,直到要负了为止。

Chips Challenge

传送门

好难啊

网格图、行、列,这提醒着我们建行点,列点,行列间连边,代表这个格子里放不放零件,不能就不用连边了,一定要放则 \([1,1]\) 的边,随意则连 \([0,1]\) 的边。

对于第二个条件,瞄一眼 \(n\),发现单行(列)可能的上限总共才只有 \(40\) 个,大胆地枚举上限,最后只要判断上限是不是 \(\le ans \times \frac{A}{B}\)

答案能二分吗?

经过多次偷数据得出:不行。比如这样的:

\(A=2,B=3\)

C.
.#

那么答案应该是 \(3\) ,但是当二分限制为 \(1\) 的时候,显然没有答案。

接下来就是烦人的第一个限制:行列相等。

如果他们相等,让它们同时加上一个流量,它们还是相等。因为他们的限制相等,所以如果让他们任意加上一个 \([0,inf]\) 的流量,行和列可以同时满流,而如果原先不相等,加上这个流量之后,还是不相等。所以要求一个满足行列相等的,我们可以在同行同列间连一条 \([inf,0]\) 的边,跑最大流看看满不满流。而行列间的边我们让其费用为 \(-1\) ,真实的零件数量即费用的绝对值。

所以现在就变成了枚举,建图,跑上下限费用流。但是真的不是很想跑上下限,怎么办呢?

怎么样才能让必选的边在最大流的情况下一定选进去?改费用!把必选的边权值付成 \(-100001\) ,最后看看费用绝对值除 \(100000\) 是不是刚好等于必须岸边条数。费用模 \(100000\) 就是答案。

好一个直接应用

简单地说,枚举每次的上限 \(lim\) ,设 \(A_i\) 表示第 \(i\) 行,\(B_i\) 表示第 \(j\) 列:

  1. \(S\)\(A_i\)\([lim,0]\) 的边,行限制
  2. \(B_i\)\(T\)\([lim,0]\) 的边,列限制
  3. 必选格 \((i,j)\),从 \(A_i\)\(B_j\)\([1,-100001]\) 的边
  4. 可选格 \((i,j)\),从 \(A_i\)\(B_j\)\([1,-1]\) 的边
  5. \(A_i\)\(B_i\)\([inf,0]\) 的边,强行保证行列相同时达到满流。

从这道题我们也可以发现,直接应用费用流可以省掉许多上下界(当然也有不能省的),即通过把必选的边费用设成极值。

回路限制

相信大家一定牢记昨天lyc的讲课内容。

回路,关键即有向图是入度=出度=1,无向图是度数=2。

进入正题(好像比前面的直接应用容易一点

占空间专用

循环格

传送门

我心中的全局最简单题。

他是个有向图回路,只要满足入度=出度=1,每个格子上有个箭头,已经保证了出度,只要保证每个格子恰好被某个箭头指到就好了。

  1. 对每个格子中的箭头建点,指向他所相邻的格子,若方向和原来不同则费用为1,否则不需要费用
  2. 源点到箭头连 \([1,0]\) 的边,表示一个箭头选一个方向
  3. 格子向汇点连1,表示每个格子只能被指一次。

最小费用最大流

【TopCoder SRM570 900】CurvyonRails

首先回路限制,这是个无向图,所以每个点度数为2。

前一题中有我们是对箭头建点,那这题的边怎么办呢。我们遇到了和开头同样的问题,网络流是有向的,无向边怎么表示。按照前面的套路,我们知道要把他分成两堆,保证只有两堆之间可以连边。

网格图常用套路:黑白染色。这样就只有黑点和白点直接可以连边了,黑点向相邻的白点连边。回路的限制很简单吧,源点到格点,格点和汇点都连 \([2,0]\) 的边,一定要满流就好。

弯路和直路怎么办呢?

对于每个点,当且仅当它的两条边被分配到了都一行或同一列,它是直道。

这启发我们把一个点拆成行点和列点,如果其中一个点被流了两次,那就要付出费用。

好像还是不好办。

我们强制让行点和列点都只连一个,然后行和列之间再连一条 \([1,1]\) 的双向边(两条单向变),流过这条边就说明一个点流了了两次。

简单来说,先黑白染色,对于某一个黑点 \(x\),将他拆成行点 \(A_x\) 和列点 \(B_x\)

  1. \(S\)\(A_x,B_x\)\([1,0]\) 的边
  2. \(A_x,B_x\) 分别向同行、同列的白点连 \([1,0]\) 的边
  3. 白点向 \(T\)\([2,0]\) 的边。
  4. \(A_x,B_x\) 间连 \([1,1]\) 的双向边。

最小费用最大流,满流才可行。

这题topcoder不太会用,所以有一道题大概可以替代

传送门

费用递增

费用递增,一个物品可以选择多次,而每次选择的代价递增。

可以对每一个物品 \(A_i\) 拆成 \(A_{i,1} \dots A_{i,x}\) 每个的费用为选 \(1 \dots x\) 次的费用,代表选某次。因为费用递增,不可能先选了后边的再选前面的,所以一定是前一条边流完了才有可能流下一条边。

本来要一次性把所有边都连完,那就完美的爆炸了,所以我们先只用每个点连一条边,等流过之后如果下一条不在图中就把他连上。

遮题解专用

美食节

传送门

考虑一个厨师贡献的代价

如果第 \(j\) 个厨师先后做了第 \(a_1,a_2,\cdots,a_w\) 种菜,做倒数第 \(k\) 道菜的时候,后面的 \(k\) 个人都等着,那么等待时间之和就是:

\[t_{a_1,j}w+t_{a_2,j}(w-1)+\cdots+t_{a_w,j} \]

那么对于同一道菜,它做得越靠后,费用就越大。

套用费用递增模型

球队收益

传送门

剪刀石头布

传送门

签到问题

课件写的是签到问题,感觉还蛮形象的。

大概就是必须到某一个点必须带着 \(x\) 个东西签一次到,那么就可以把这个点理解为早上和晚上,早上签到,晚上离开。

早上你要上交 \(x\) 个物品,暂存在汇点(假装汇点是个大boss),即早点向汇点连 \([x,0]\) 的边

晚上你可以从源点重新拿回这 \(x\) 个物品(汇点下班了把东西转交给源点了),继续你的下一次签到。即源点向晚点连 \([x,0]\) 的边。

合法方案一定是满流的。

遮题解

餐巾计划

传送门

我们可以理解为,第 \(i\) 天早上,餐厅要发给顾客 \(x_i\) 块餐巾,可以买餐巾,洗衣店会把前几天送来的今天洗完的餐巾送回来。每天晚上顾客把所有餐巾都还回来。每天晚上餐厅可以把餐巾送到快(慢)洗点洗,当然也可以堆着不洗,直接放到明天(但是他不能发给顾客,所以等于屯了一天直接屯到第二天晚上)。

把每一天拆成早点 \(A_i\) 和晚点 \(B_i\)

早上能干吗要干嘛?

  1. 发餐巾:从 \(A_i\)\(T\)\([x_i,0]\) 的边,必须要满流
  2. 买餐巾:从 \(S\)\(A_i\)\([inf,p]\) 的边
  3. 收洗过的餐巾:见下

晚上能干吗?

  1. 回收脏餐巾:从 \(S\)\(B_i\)\([x_i,0]\) 的边(可以理解会汇点和源点间有无形的边汇点收到的会回流)
  2. 洗餐巾:快洗—— \(B_i\)\(A_{i+a}\)\([inf,b]\) 的边;慢洗——\(B_i\)\(A_{i+b}\)\([inf,a]\) 的边。
  3. 直接留着扔给明天:\(B_i\)\(B_{i+1}\)\([inf,0]\) 的边。

跑最小费用最大流,一定是满流。

posted @ 2020-08-15 14:28  flyfeather  阅读(184)  评论(0编辑  收藏  举报