斜率优化总结

适用范围:

斜率优化是DP的一种优化,适用于转移方程式中除了f[i]和f[j]还和其他和ij有关的变量的DP,例如:f[i]=min(f[j]+(a[i]-a[j])^2)(a数组递增)

实现方法:

以上面的方程为例。
step1:展开:
假设f[i]必定由f[j]转移而来,则 f [ i ] = f [ j ] + ( a [ i ] − a [ j ] ) 2 = f [ j ] + a [ i ] 2 − 2 ∗ a [ i ] ∗ a [ j ] + a [ j ] 2 f[i]=f[j]+(a[i]-a[j])^2 =f[j]+a[i]^2-2*a[i]*a[j]+a[j]^2 f[i]=f[j]+(a[i]a[j])2=f[j]+a[i]22a[i]a[j]+a[j]2
step2:转化:
f [ i ] + 2 ∗ a [ i ] ∗ a [ j ] = f [ j ] + a [ j ] 2 + ( a [ i ] 2 ) f[i]+2*a[i]*a[j] = f[j]+a[j]^2 +(a[i]^2) f[i]+2a[i]a[j]=f[j]+a[j]2+(a[i]2)
b + k x = y b + k x = y b+kx=y
(a[i]^2可以省略不看,因为在实际做的过程中会相互抵消)
我们把所有的j都抽象成点对(x,y),由转化的结果可知是(a[j],f[j]+a[j]^2)
那么我们就可以看做是和j有关的一条直线,斜率是2a[i],而我们想要求的f[i]最小值就是这条直线的截距最小值。
这是我们就可以思考怎样的直线能使这个截距最小。在我们构造出的点图中,因为斜率一定(2
a[i]), 所以一定是在其下凸壳上(如下图)
这里写图片描述
以上就是斜率优化的原理。

特殊情况:

如果只是一般的斜率优化,就要用一些高大上的算法来维护凸壳,但是并不会。。。
但是好在有很多斜率优化的DP题都有一些特殊情况,比如说对于这题来说,x坐标是递增的,即a[i]递增。不仅如此,这题的斜率k也是递增的,即2*a[i]递增。那么我们只要写一个单调队列来维护一下就好了。

附:维护单调队列方法:
每一次将队列首head和head+1求一下斜率,记作xl(que[head],que[head+1]),求的方法也就是数学中的两点连线的斜率求法,即为(ya-yb)/(xa-xb)。
将其与当前i的斜率比较,如果小于它,那么队首对于后面的元素的修正就没有用了(显然可以找到更优的,即y坐标更小的),就将其踢出队列。
然后用队首来修正f[i](因为是单调队列,所以此时队首的y坐标肯定最小)。
接下来再将xl(que[tail-1],que[tail])与xl(que[tail],i)比较,如果前者大于后者就可以将其踢出队列,理由和前面一样。最后将i加到对尾就行了。

示例代码:

    for (int i=1;i<=n;i++) {
        while (head<tail&&xl(que[head],que[head+1])<x[i]) head++;
        f[i]=f[j]... (修正)
        while (head<tail&&xl(que[tail-1],que[tail])>xl(que[tail],i)) tail--;
        que[++tail]=i;
    }

OVER。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值