费用流
\(\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\) 列:
- 从 \(S\) 到 \(A_i\) 连 \([lim,0]\) 的边,行限制
- 从 \(B_i\) 到 \(T\) 连 \([lim,0]\) 的边,列限制
- 必选格 \((i,j)\),从 \(A_i\) 向 \(B_j\) 连 \([1,-100001]\) 的边
- 可选格 \((i,j)\),从 \(A_i\) 向 \(B_j\) 连 \([1,-1]\) 的边
- 从 \(A_i\) 到 \(B_i\) 连 \([inf,0]\) 的边,强行保证行列相同时达到满流。
从这道题我们也可以发现,直接应用费用流可以省掉许多上下界(当然也有不能省的),即通过把必选的边费用设成极值。
回路限制
相信大家一定牢记昨天lyc的讲课内容。
回路,关键即有向图是入度=出度=1,无向图是度数=2。
进入正题(好像比前面的直接应用容易一点
占空间专用
循环格
我心中的全局最简单题。
他是个有向图回路,只要满足入度=出度=1,每个格子上有个箭头,已经保证了出度,只要保证每个格子恰好被某个箭头指到就好了。
- 对每个格子中的箭头建点,指向他所相邻的格子,若方向和原来不同则费用为1,否则不需要费用
- 源点到箭头连 \([1,0]\) 的边,表示一个箭头选一个方向
- 格子向汇点连1,表示每个格子只能被指一次。
最小费用最大流
【TopCoder SRM570 900】CurvyonRails
首先回路限制,这是个无向图,所以每个点度数为2。
前一题中有我们是对箭头建点,那这题的边怎么办呢。我们遇到了和开头同样的问题,网络流是有向的,无向边怎么表示。按照前面的套路,我们知道要把他分成两堆,保证只有两堆之间可以连边。
网格图常用套路:黑白染色。这样就只有黑点和白点直接可以连边了,黑点向相邻的白点连边。回路的限制很简单吧,源点到格点,格点和汇点都连 \([2,0]\) 的边,一定要满流就好。
弯路和直路怎么办呢?
对于每个点,当且仅当它的两条边被分配到了都一行或同一列,它是直道。
这启发我们把一个点拆成行点和列点,如果其中一个点被流了两次,那就要付出费用。
好像还是不好办。
我们强制让行点和列点都只连一个,然后行和列之间再连一条 \([1,1]\) 的双向边(两条单向变),流过这条边就说明一个点流了了两次。
简单来说,先黑白染色,对于某一个黑点 \(x\),将他拆成行点 \(A_x\) 和列点 \(B_x\):
- \(S\) 到 \(A_x,B_x\) 连 \([1,0]\) 的边
- \(A_x,B_x\) 分别向同行、同列的白点连 \([1,0]\) 的边
- 白点向 \(T\) 连 \([2,0]\) 的边。
- \(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\) 个人都等着,那么等待时间之和就是:
那么对于同一道菜,它做得越靠后,费用就越大。
套用费用递增模型
球队收益
剪刀石头布
签到问题
课件写的是签到问题,感觉还蛮形象的。
大概就是必须到某一个点必须带着 \(x\) 个东西签一次到,那么就可以把这个点理解为早上和晚上,早上签到,晚上离开。
早上你要上交 \(x\) 个物品,暂存在汇点(假装汇点是个大boss),即早点向汇点连 \([x,0]\) 的边
晚上你可以从源点重新拿回这 \(x\) 个物品(汇点下班了把东西转交给源点了),继续你的下一次签到。即源点向晚点连 \([x,0]\) 的边。
合法方案一定是满流的。
遮题解
餐巾计划
我们可以理解为,第 \(i\) 天早上,餐厅要发给顾客 \(x_i\) 块餐巾,可以买餐巾,洗衣店会把前几天送来的今天洗完的餐巾送回来。每天晚上顾客把所有餐巾都还回来。每天晚上餐厅可以把餐巾送到快(慢)洗点洗,当然也可以堆着不洗,直接放到明天(但是他不能发给顾客,所以等于屯了一天直接屯到第二天晚上)。
把每一天拆成早点 \(A_i\) 和晚点 \(B_i\) 。
早上能干吗要干嘛?
- 发餐巾:从 \(A_i\) 到 \(T\) 连 \([x_i,0]\) 的边,必须要满流
- 买餐巾:从 \(S\) 到 \(A_i\) 连 \([inf,p]\) 的边
- 收洗过的餐巾:见下
晚上能干吗?
- 回收脏餐巾:从 \(S\) 到 \(B_i\) 连 \([x_i,0]\) 的边(可以理解会汇点和源点间有无形的边汇点收到的会回流)
- 洗餐巾:快洗—— \(B_i\) 到 \(A_{i+a}\) 连 \([inf,b]\) 的边;慢洗——\(B_i\) 到 \(A_{i+b}\) 连 \([inf,a]\) 的边。
- 直接留着扔给明天:\(B_i\) 向 \(B_{i+1}\) 连 \([inf,0]\) 的边。
跑最小费用最大流,一定是满流。