码迷,mamicode.com
首页 > 其他好文 > 详细

「斜率优化」解析及例题

时间:2018-07-23 21:11:32      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:装箱   队列   转化   传送门   line   www   出队   问题   为我   

前言

  我们知道单调队列可以用来优化动态规划,当状态转移方程可以被表示为f[i] = (只与j有关的) + 一些常数 时便可以用单调队列来保存j来O(1)完成寻找j的过程,因此将$O(n^2)$优化为了$O(n)$

  那么如果当有一个转移方程变为了f[i] = (f[j] + 与i有关的)^2 ...这种情况时,我们发现展开的时候有f[j]*s[i]这类的项,因此不能再用单调队列直接来进行优化了,这时候就要用到斜率优化。

例题分析

  空说没用,举例来讲吧:

  传送门:>[HNOI2008]玩具装箱TOY<

题意:给你n件物品,物品i被压缩成一维以后长度为C[i]。现在你要把这些玩具按顺序放进几个一维容器中。其中制作一个长度为X的一维容器所需要的费用的是$(X-L)^2$。如果在一个一维容器中放入多个玩具,则每两个相邻的玩具之间要放进一个长度为1的东西用来隔离。想造几个容器就造几个容器。问把所有玩具装好的最小费用。数据范围$N \leq 50000$

  首先,很容易得出一个$O(n^2)$的转移方程$$f[i] = f[j] + (sum[i] - sum[j] + i - (j+1)-L)^2$$

整理得$$f[i] = f[j] + (sum[i]+i-(sum[j]+j)-(L+1))^2$$

设$s[k] = sum[k] + k, L = L+1$,则$$f[i] = f[j] + (s[i]-(s[j]+L))^2$$

展开得$$f[i] = f[j] + s[i]^2 - 2 * s[i] * (s[j] + L) + (s[j] + L)^2$$

移项$$f[j]+s[i]^2+(s[j]+L)^2 = 2 * s[i] * (s[j] + L) + f[i]$$

  至此,我们已经将转移方程做了一些改变。由于当前考虑i,我们可以把i作为已知量,未知的是j。因此可以将有关j的作为变量来得到一个直线方程(一次函数):

  $$f[j]+s[i]^2+(s[j]+L)^2 = 2 * s[i] * (s[j] + L) + f[i] \Longleftrightarrow y = kx + b$$

  因此,对于所有可供我们转移的j都可以看做坐标$(s[j] + L, f[j]+s[i]^2+(s[j]+L)^2)$。同时我们容易发现,斜率是一个常数,我们要求的$f[i]$是该直线的截距

  所以我们的问题可以转化成这样:

    给出一条已知斜率的直线,求当该直线经过其中一个点时的最小截距。

  这个问题可以理解成:当一条直线从下往上平移时,碰到第一个点时的截距。

  很容易发现,这个点一定是最外层的点(也就是凸包上的点)。因此我们可以维护一个下凸包,并且可以保证,下凸包内相互连接的线段的斜率依次递增。

  想象一下画面,也很容易发现我们碰到的第一个点两边线段的斜率一定左边小于他,右边大于它。也就是说直线刚好顶在一个尖角上。

  因此只要求出这个尖角就好了。

  此时我们可以用单调队列来维护。由于直线的斜率是$2 * s[i]$,所以依次考虑i时,斜率是不断会递增的。因此所有斜率小于当前直线的线段的左端点可以全部踢掉了,因为以后他们也不会再有用了。这就好像单调队列一样。好了,此时的那个点就是我们要找的那个点了。依据状态转移方程得到f[i],并且i作为一个新的点加入点的行列。此时还是像单调队列一样考虑。看看i能否放在目前维护的凸包的最后面,并且我们需要保证的是线段的斜率依次递增。所以我们不断判断来踢出尾部的节点。踢出尾部节点的正确性也非常好证明:无论如何,由于i与结尾t的连线斜率较小,所以以后的直线肯定先碰到i再碰到t,并且i会永远存在,所以t就不必要存在了。

  但是我们注意到了,在我们的y坐标中拥有$s[i]^2$,这就不仅仅与i有关了,还与i有关?其实这与i根本没有关系,因为我们在算斜率时分子是两个y坐标的差,而对于同一条直线,$s[i]^2$显然是相等的,所以他们在做差时就会被减掉从而被抵消。更一般的,所有与j不想关的都会被减掉,无论是x坐标还是y坐标。所以本题的x,y坐标可以被改成$(s[j], f[j]+(s[j]+L)^2)$

总结

  现在对斜率优化动态规划的题目做一个总结,如下:

  1. 依据题目,列出$O(n^2)$或更别的待优化的状态转移方程

  2. 对方程进行变形成为$y = kx + b$的形式,令截距为f[i]

  3. 得到x,y坐标,同时去除不与j相关的冗余项

  4. 考虑得到的截距是要最大还是最小,从而维护上凸包还是下凸包

  5. for循环,先踢出队头的,从而得到符合要求的进行转移,再踢出队尾的

  6. 输出答案

「斜率优化」解析及例题

标签:装箱   队列   转化   传送门   line   www   出队   问题   为我   

原文地址:https://www.cnblogs.com/qixingzhi/p/9356829.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!