zoukankan      html  css  js  c++  java
  • 【以前的空间】斜率优化的一点点总结

      今天有看了一道dp题,发现好像裸不能过,应该是要斜率优化,结果发现自己那点傻×智商早把这东西忘得差不多,而且当时也是有点乱不是弄得很懂。于是又花了一个早上来整理下。

      《用单调性优化动态规划》  

       这个东西的话很好。但是由于我蒟蒻所以看不懂。先找了模板题到网上找题解,然后跟着题解自己推。那么我就用《[ZJOI2007]仓库建设》来推吧!

      首先很容易写出状态转移方程

      f[i]:=Min(f[j]+w[j,i])+c[i]

      其中f[i]表示前i个的最优状态且在i建一个仓库,j表示上一个仓库的位置。

      w[j,i]=p[j+1]*(x[i]-x[j+1])+p[j+2]*(x[i]-x[j+2])+……+p[i-1]*(x[i]-x[i-1])+p[i]*(x[i]-x[i])(p.s 按照论文里面的说法:为了之后的式子好看保留最后一项)。

      于是朴素的话就是枚举i之前的j,这样复杂度是o(n²)。

      我们把w[j,i]这个式子展开,再合并,得到

      w[j,i]=x[i]*(p[j+1]+p[j+2]+……+p[i])-(p[j+1]*x[j+1]+p[j+2]*x[j+2]+……+p[i]*x[i]);

      记sum1[i]=Σp[i],sum2[i]=Σp[i]*x[i],然后w[j,i]可化为

      w[j,i]=x[i]*(sum1[i]-sum1[j])-(sum2[i]-sum2[j])

            =-x[i]*sum1[j]+sum2[j]+x[i]*sum1[i]-sum2[i];

      然后把w[j,i]带入原来的方程得到

      f[i]:=Min(f[j]+sum2[j]-x[i]*sum1[j])+x[i]*sum1[i]-sum2[i]+c[i] (后面几个都是根据i唯一确定的,所以可以从Min中提取出来)

      然后就是斜率优化的东西了!

      把Min中由i确定的看成是系数,也就是这个方程中的-x[i],先设为a。

      把与系数相乘的那个设为x,也就是这个方程中的sum1[j]。

      把剩下的那些东西都设为y,也就是这个方程中的sum2[j]+f[j]。

      最后把f[i]设为G。

      然后就变成G=ax+y,进而得到y=-ax+G。之后就是论文里面一些balabala的东西了。

      但是我觉得这样解释不如另一种解释斜率优化好(便于像我这样的蒟蒻理解):

      

      设j,k为i之前两个决策点,且i>j>k,以及j决策要优于k决策

      那么f[j]+w[j,i]<f[k]+w[k,i]

      也就是f[j]+sum2[j]-x[i]*sum1[j]<f[k]+sum2[k]-x[i]*sum1[k]

      移项就是f[j]+sum2[j]-f[k]-sum2[k]<x[i]*(sum1[j]-sum1[k])

      然后用之前说的x,y,a代替就是

      y(j)-y(k)<a*(x(j)-x(k))

      然后x是单调递增的所以x(j)>x(k),所以除过去得到

      (y(j)-y(k))/(x(j)-x(k))<a 然后这个式子不就是斜率的公式么……

      所以若k<j且j优于k则满足上面这个式子。

      然后就是维护规则了。

      维护一个单调队列,里面记录决策的位置,且里面的决策的位置都是单调递增的。

      首先对于当前i来说,它的最优决策就是满足(y(j)-y(k))/(x(j)-x(k))<a的最大一个j。于是从队头head开始,如果(y(head+1)-y(head))/(x(head+1)-x(head))<a就是head++,这样就可以找到(y(j)-y(k))/(x(j)-x(k))<a的最大一个j。也就是这时的head就是i的最优决策,于是f[i]=f[q[head]]+w[head,i]+c[i]。

      然后就是把i加入队列中,同样也是要满足(y(j)-y(k))/(x(j)-x(k))<a,不过是要考虑进三个决策之间斜率的关系。由于斜率是单调递增的,且(y(tail)-y(tail-1))/(x(tail)-x(tail-1))<a(tail),(y(i)-y(tail))/(x(i)-x(tail))<a(i),所以(y(tail)-y(tail-1))/(x(tail)-x(tail-1))<(y(i)-y(tail))/(x(i)-x(tail)),按照这个规则维护,如果tail不符合这个规则那么tail--,直到tail符合,然后把决策i加入决策队列中,即q[++tail]=i。

      然后就是这样了!

  • 相关阅读:
    团队冲刺第四天
    团队冲刺第三天
    团队冲刺第二天
    团队冲刺第一天
    全球疫情地图显示
    团队博客——keep running视频+PPT介绍
    周总结7
    人月神话阅读笔记03
    Java枚举类型的使用,数值的二进制表示
    四则运算器
  • 原文地址:https://www.cnblogs.com/Macaulish/p/6492085.html
Copyright © 2011-2022 走看看