zoukankan      html  css  js  c++  java
  • DP——斜率优化

    这几天genius都在学习斜率优化,看了一些大佬的博客,初学时感觉斜率优化是一个蛮难懂的姿势(废话,省选内容不难懂有鬼啊??!!

    在这里写一篇博客为了记载一下学习历程,害怕自己以后忘了,不敢说能让读者彻底明白(不过相信各位都是大佬),如果能让读者受益,那是再好不过的。

    这里感谢网上某位大佬博客的支持

    这里将斜率优化分为数,形两类来进行理解,读者可以选择适合自己的方式来理解

    【数】

      对于某一类型的dp方程

    f[i]=Min(a[i]b[j]+c[j]+d[i])

     其中a[x],b[x],c[x],d[x]是关于x的函数,且b单增。——————【1】

      按照一贯的套路,先数学归纳法证明决策单调性。

      1.归纳假设:

        假设有i前两个决策点j,k(j<k),且k的决策要比j好,即:

    a[i]b[j]+c[j]+d[i]>=a[i]b[k]+c[k]+d[i],j<k——————【2】

      2.归纳推理:

        此时后面有状态i+1,这里我们为了简单起见,不妨设a[i+1]=a[i]−v,v>0,也就是a单调递减。

    即证:a[i+1]b[j]+c[j]+d[i+1]>=a[i+1]b[k]+c[k]+d[i+1]

    (a[i]−v)b[j]+c[j]+d[i+1]>=(a[i]−v)b[k]+c[k]+d[i+1]

    化简得:a[i]b[j]+vb[k]+c[j]>=a[i]b[k]+vb[j]+c[k]

    由【2】得:a[i]b[j]+c[j]>=a[i]b[k]+c[k]

    由【1】得:b[k]>b[j]

    又∵v>0

    vb[k]>=vb[j]

    得证

      所以,决策单调性是存在的。我们将由决策单调性得出的式子展开,化成斜率式:

    a[i]b[j]+c[j]+d[i]>=a[i]b[k]+c[k]+d[i],j<k

    a[i]>=c[k]−c[j]b[k]−b[j]

     记斜率

    slope(i,j)=c[k]−c[j]b[k]−b[j]

     然后发现这个东西很符合单调队列的尿性:

    1. a[i]>=slope(q[l],q[l+1])。因为q[l]在q[l+1]之前加入,那么显然这个式子就表示q[l]决策不如q[l+1]优,我们可以将队首pop掉。
    2. slope(q[r−1],q[r])>slope(q[r],i)。假设我们在后面存在一个a[t]使得a[t]>=slope(q[r−1],q[r])那么等到pop了q[r−1]之后,a[t]一定也会>=slope(q[r],i),q[r]也会被pop。所以说q[r]实际上是无用的,我们可以直接将它pop掉。

      问题就这样优化到了O(n)。


    【形】

      dp方程:

    f[i]=Min(a[i]b[j]+c[j]+d[i]),b[j]单增

     

      我们这里沿用上面“数”的条件:a单减,b单增。

      移项:

    a[i]b[j]+f[i]=c[j]+d[i]

     是不是很像直线的斜截式:a[i]为直线的斜率;直线过点:(b[j],c[j]+d[i]) f[i]即为直线在Y轴上的截距。

      

     

      可以看出,因为f[i]要尽可能小,所以我们把之前小于ij画在平面直角坐标系上,一如线性规划,把这条斜线自下往上平移时遇到的第一个点,即能使目前状态有最小值的点。于是我们需要维护一个下凸壳,把那些肯定不会贡献的点删掉。

     

      我们用一个单调队列维护这个凸壳,因为要保证凸壳的下凸性,所以我们显然可以得到单调队列pop队尾的条件:slope(q[r−1],q[r])>slope(q[r],i)。

      考虑什么情况下pop队首元素(这里我们的讨论都是基于f[i]取最小值的情况下的):

    1. 斜率a[i]单增(因为a单减)。a[i]>slope(q[l],q[l+1])。
    2. 斜率不单调。无法pop队首,二分或者三分查找队列中的最优解。二分做法:假设你要在上凸包上二分找斜率为k的切线。取中间的mid号点,如果mid+1存在且与mid点的斜率小于k,则l=mid+1;如果mid−1存在且与mid点的斜率大于k,则r=mid−1;如果上面两条都不满足,则mid就是切点。

      不错,你一定已经发现第一种情况所对应的维护方式不是跟之前所说“数”的单调队列维护方式一模一样吗,没错,其实这只是两种不同的解题方式所得出来的同样的结果

      两种方法各有优缺点吧,“形”的角度比较方便理解,对于更高深的cdq分治维护凸包可以比较清晰的了解。但是遇到复杂的dp方程以及决策单调性证明就得靠“数”了(比如国王饮水记),看情况使用吧。

      之前说的决策单调性是斜率优化的基础这句话其实并不严谨,像这种从图形角度来求解的斜率优化就并没有用到决策单调性。想一想如果能证明决策单调性,那么一定就是对ab的单调性有要求的,否则的话就是什么斜率不单调啦,在凸包上二分啦什么的。

      这就是斜率优化啦。

    【个人一点小见解】

    1.个人认为斜率优化的数的方式是比较好理解的,我们每次找到动态规划的状态转移方程后就可以直接转换

    2.斜率优化只适用于具有单调性的转移方程,即最后简化后的等式左右中的一方必定有一个是给定单调的函数,譬如前缀和。

    3.每次斜率优化都要设更优解的自变量,然后用更优解来维护斜率

    4.保证储存斜率的队列单调

    5.很值得注意到一点,对于初学者而言我们可能会想,为什么可以把斜率转换成这样的形式,其实不然,斜率的形式并不唯一,我们不需要去刻意仿照别人的斜率等式,只要二者等价,即都可以求出正解(具体可参见题解报告——特别行动队)

    6.注意正负,可以看见斜率的会有除法运算,记得不等式除负数时要变号(可能就我这么傻,不会变号),不然公式推错那就GG了

    7.最后就是要在做题中理解斜率优化的妙用,可以参考一下他人的代码,或许会大有启发。

     

     

  • 相关阅读:
    c#基础练习
    一款很厉害的死循环代码
    文字变色逐个出现的特效源码
    IOS开发之UILabel动态高度设置方法
    慎重选择容器类型
    Mac下显示隐藏文件 以及修改 hosts文件内容
    SharePoint 如何使自己的网页自动跳转
    位置和地图:地图的使用
    谈话Java在ThreadLocal理解类
    Android 滑动界面实现---Scroller类别 从源代码和开发文档了解(让你的移动布局)
  • 原文地址:https://www.cnblogs.com/genius777/p/8686929.html
Copyright © 2011-2022 走看看