Codeforces 1525D - Armchairs
条评论题意
有$n$张椅子一字排开,编号为$1-n$,一张椅子上只能坐$1$个人。其中$k(k \leq \lfloor \frac{n}{2} \rfloor)$张椅子上面坐着人,你需要使这$k$个人都挪到另外的椅子上,一次只能把一个人从他现在坐着的椅子$i$挪到另一张空椅子$j$上,代价为$|i-j|$。
思路 - 各路神仙算法记录 :)
首先,第一眼看到这道题目,我想到的是一个二分图的匹配问题,已经被占的椅子作为一边,其他椅子作为另外一边,然后建图连边,两两配对。但是,我想要求出最小的代价,就需要想一想了。
(其实后面学了之后发现,是典型的$KM$算法求二分图最大权匹配问题,我傻了)
分析一下,由于$k \leq \lfloor \frac{n}{2} \rfloor$,因此一定存在一个解。然后,我们可以推断,一定存在一个最优解,椅子的状态改变不会超过一次,即不会有人把空椅子变成坐着人的椅子再变成空椅子。
也就是说,我们只要确定每个人最后能够到达哪个椅子,就能够得到最优解。二分图的做法貌似可以,但没那么好写。那么,想别的方向。直观上看起来是可以贪心的,排个序之后再选择最近的椅子?但是很快就把贪心给$hack$掉了,尝试添加一个反悔的操作,但好像在该题也不太适用,因为每个人都需要坐在新的椅子上。
(后面了解了模拟费用流之后,感觉有点像反悔贪心?)
回到最开始的图论想法,有点像最小费用最大流,超级源点连接已经被占的椅子,超级汇点连接其他椅子,流量为$1$,费用为$0$,限制最后的最小费用是从原有的$k$个人身上发出,从另外$n-k$个椅子上汇集。
现在需要找到一种连接椅子间的方式,把这个问题表示出来。为了表示代价,可以设相邻两个椅子的费用为$1$,容量设为$n$,这样能够表达第一张椅子到最后一张椅子的代价。
建图完毕,跑$Dinic$,最小费用最大流,时间复杂度理论最坏$O(n^2m)$?但是这题应该卡不到最坏复杂度。
但是,很不幸的,$TLE41$了。
1 |
|
由于代码是拿我很早以前的模板改的所以有点丑。
下面开始半懂不懂,仅供记录,主要是为自己学习留个底(
然后我百度了一下,发现有人推荐使用$zkw$费用流…在某些情况下跑的飞快(雾
我找了个板子(板子入口),测试了一下,确实飞快跑过了…
据说在费用范围较小,流量较大,或者增广路径比较短的图中,使用$zkw$费用流有明显提速,反之则$zkw$费用流可能比原始费用流更慢(出处见下一解法的文档)。
以后在专门写一篇总结一下网络流(
这道题只要建完边就只剩下选择算法的问题了(
这一题也可以使用$KM$来做,实际上,$KM$解决的就是这样的二分图最大权匹配问题(
1 |
|
而后,我在$Codeforces$评论区,还看到有一种模拟费用流的做法:
具体做法见该文档$Problem \ 2$:模拟费用流问题 陈江伦
本题$O(n)$解法如下(来自$Codeforces$评论区,出处见代码顶部):
1 | /* |
同样是模拟费用流,还有个$O(nlogn)$解法,没有那么抽象。
摘自Educational Codeforces Round 109 (Div. 2)] 解题报告 | 赤红幻想 (reimu.red)
(个人感觉有点像反悔贪心?)
1 |
|
经历了这么多图论做法,我发现,$dp$的做法是多么美妙(
设$dp[i][j]$,为前$i$个人,安排在前$j$个椅子被成功处理的最小代价(
为了使得处理得到的是最小代价,初始化为极大值。
然后,分析边界情况,$dp[0][j] =0$,$dp[i][0] = inf$。
考虑转移方程,分两种情况:
- $dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + abs(b[i] - c[j]))$,把第$i$个人移动到第$j$个椅子上。
- $dp[i][j] = min(dp[i][j], dp[i][j - 1])$,前$i$个人在前$j-1$的椅子上被安排好了。
由此进行转移即可。
代码如下:
1 | /* vegetable1024 | oi-liu.com | Maybe Lovely? */ |
结尾
$wsfw$
本篇”题解“不像往常主要记录了自己的思路,而是记录了各位大佬的写法,比较水,主要是先记录下来帮助自己学习。
希望有朝一日我的博客也会被人引用(