CodeVS 1237。
粗浅地学习了带上下界的网络流的人的代码的时间开销:1472ms。
领悟二分图精髓的人的代码的时间开销:18ms。
两种建图的顶点数相同,我的边数是后者的2/3。但是增广的次数可能很多。
优雅的模型
约束是每天的餐巾够用,目标是使费用最小。每天的餐巾有三种来源:新买的,m天前送到快洗部的,n天前送到慢洗部的。每天的餐巾有三种去路:延期处理,送到快洗部,送到慢洗部。网络流模型擅长处理的是小于等于号,然而这里是“够用”即大于等于。(1) 如果总是存在一种刚好够用的方案,它显然优于其他有冗余的方案。今天多用一些餐巾的好处是能多洗一些餐巾以备后用……这是不必要的。今天多用的餐巾如果是买的,要用的那天再买,能省去清洗费用;如果是洗的,从它被使用的那天起延期处理,今天清洗即可,今天用不着使用它。(2) 刚好够用的方案总是存在。所以,根据(1)(2),在费用最小的目标下,“够用”可以改成“恰好够用”。
- 上面的分析中,我们区分了“今天使用的”和“今天清洗的”。把“今天清洗的”作为X集合,“今天使用的”作为Y集合,我们能够建立二分图模型。今天使用的=今天清洗的=今天的需求,S->Xi,Yi->T,容量为ri,费用为0,求最大流把它们流满即满足约束。它们必能满流,因为其他边的容量都是正无穷的,见下文。
- 新买的:S->Yi,容量inf,费用p。
- 快洗:Xi->Y(i+m),i+m<=N,容量inf,费用f。
- 慢洗:Xi->Y(i+n),i+n<=N,容量inf,费用s。
- 延期处理:Xi->X(i+1),i< N,容量inf,费用0。
就是这样。
这个模型使我欣赏的地方:
1. 通过分析,把>=转为=,由于流的容量限制(<=),流量最大时满足了约束(取得等号)。“最小费用”、“最大流”两个约束很好地统一了。
2. “从源点流出的=流入汇点的”——广义的流量平衡。平时我们讲流量平衡,都是以一个顶点为对象,流入=流出。别忽视了整体。
我的模型
写完上面的,自惭形秽。
- 每个点i拆成两个,中间连边,容量为ri,费用为0。即in(i)->out(i)。
- S->in(i),容量inf,费用为p。
- out(i)->in(i+m),i+m<=N,容量inf,费用为f。
- out(i)->in(i+n),i+n<=N,容量inf,费用s。
- out(i)->out(i+1),i< N,容量inf,费用0。
- out(N)->T,容量inf,费用为0。
我拆点不是看到了二分图,而是为了给节点赋容量。
对比两种模型,我的out很像二分图里的X,in很像二分图里的Y。实际上,用上下界网络流的方法,分离必要弧,建立附加源S’、汇T’,连接原T->S,两个模型是等价的。S’->S会经过两条容量为inf,费用为0的边,费用p相当于由S’付。但是,由于没有理清对第1点里“容量”的真正要求,一直觉得得求最小/大流,我使用了以下非常规方法。
第1点的“容量”,现在想来,我实际想表述的是上界=下界=ri。之前没意识到,直接跑S-T最小费用最大流,企图让这些边流满。然而流满它们的方式很多,最大流等于r1+r2+…+rN,不是我想要的。这里,“最小(可行)费用”和“最大流”未能统一。
做了些修改。用带上下界的网络流的方法,先跑S-T可行流,再跑T-S最大流。我直接建了跑完S-T可行流后的残存网络(去掉了一些不必要的弧)。接下来跑T-S最小费用最大流吗?好像不对头。这样求出

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



