比较重要并且难想,需要多加练习。
费用流
1.定义
费用流是指所有最大可行流中,费用最小(最大)值。
前提是最大可行流。
给每条边幅赋一个费用,则总费用为:
如果有最大可行流的话,一定有最小费用最大流。
因为可行流满足两个条件:
满足容量限制;
满足容量守恒。
但是有一些最小费用无法求出来。
如图,该费用流无法用后面的方法求出来。
2.求法
Edmonds-Karp 算法为基础。
将 bfs 换为 spfa,这样每一次都是最短路(即最小代价)。
证明:
假设当前的 f1 是最小费用,经过一次 spfa 后,得到 f2,新的为 f
假设 f 不是最小费用,设 f’ 是最小费用,经过 f2‘ 得到。
那么 $|f’|=|f|$。
因为都由 f1 扩展而来,可得 $|f2’|=|f2|$
又$w(f)=|f|*s(f)$,可得 $s(f2’)<s(f2)$,与最短路矛盾。
所以原命题成立。
如果原图有负权回路,那么 spfa 会陷入死循环。
要用到”消圈”的方法,这里不过多赘述。
建图时,将费用改为$p(u,v)=-p(v,u)$。
一般情况下,只要原图不存在负环,那么残留网络也不会。
(因为流量不会绕圈,所以反向边也不会成环)。
1 | void add(int a,int b,ll c,ll d) |
3.做题方式
与最大流相似,都是先将原问题转化为一个网络流,然后证明解是一一对应的,最后证明原答案与新图的答案是相关的。
4.例题
T1:
先建立一个流网络,从源点到仓库建立 $a(i),0$ 的边,从零售店到汇点建立 $b(i),0$ 的边,从仓库到零售店建立 $+\infty,c(i,j)$ 的边。
易得,最大流一定是满流(因为中间都是 $+\infty$)。
证明略,比较容易。
又因为,只有从仓库到零售店的流才会花费,所以最小费用就是原问题的费用。
注意最小最大费用流都要求。
我用传参的方式防止了代码过长。
1 |
|
T2:
可以发现,如果一个站比平均值多,他就要输出,否则就要输入。
可以将货物看为流量,将站分为2个部分,但是不是所有边都是连接两部的,也有一部之间的。
最小费用最大流即可。
1 |
|
T3:
和第一题类似。
1 |
|
T4:
只是要拆点。
同样的建图,只不过这道题比较麻烦,需要处理3个问。
主要讲一下 3 个问题的衔接。
第一个转到第二个时,我们将所有点内的边都设为 $+\infty$
第二个转到第三个时,我们将所有点间的点再都设为 $+\infty$
但是由于每个出发点只能有一次出发,所以不能更新。
看代码。
1 |
|
T5:餐巾计划问题
对于每一天,干净毛巾的毛巾只可能来自 3 种情况:
新买的
快洗部
- 慢洗部
脏的毛巾也只可能来自3种情况:
留到下一天
送到慢洗部
送到快洗部
我们可以将每天用完的旧毛巾看做点,将每天要用的新毛巾看做另外的点
新毛巾就可以从 $s$ 到该点,费用为 $p$
每天都要从该点流 $r(i)$ 到汇点,相当于用了 $r(i)$
快洗与慢洗就相应连到相应相应早上的点。
从 $s$ 到晚上的点流量为 $r(i)$,相当于得到 $r(i)$ 条旧毛巾。
从早上的点到汇点一定是满流,否则就会使货不应求。
但源点开始的点可以不用满流(可以浪费)。
并且,前一天的脏毛巾可以留到下一天。
综上,建图如下(设早上点为$a(i)$,晚上点为 $b(i)$):
$add(s,b(i),r(i),0)$
$add(a(i),t,r(i),0)$
$add(b(i),b(i+1),+\infty,0)$
$add(s,a(i),+\infty,p)$
$add(b(i),a(i+n),+\infty,s)$
$add(b(i),a(i+m),+\infty,f)$
注意,$s$ 与 $t$ 只是形式上的源汇点,没有什么实际意义,它象征着整个网络流的正常运作,而与本问题无关。
1 |
|