动态规划(DP)——斜率优化

本文介绍了一种针对特定形式动态规划方程的优化方法,通过维护斜率递减的单调队列来达到O(1)选取最优状态的目的。

形式

形如

dp[i]=max(dp[j]a[i]×b[j]+c[j])+d[i]dp[i]=max(dp[j]−a[i]×b[j]+c[j])+d[i]
的dp方程
a[x],b[x],c[x],d[x]a[x],b[x],c[x],d[x]为一些与x有关的式子)
(需保证b[x]满足单调性)
如果是min,则后面的过程反过来,自己理解去。

思路

为了O(1)O(1)选出最优的j,假设dp[j]dp[j]优于dp[k]dp[k],且b[j]>b[k]b[j]>b[k]
即,

dp[j]a[i]×b[j]+c[j]>dp[k]a[i]×b[k]+c[k]dp[j]−a[i]×b[j]+c[j]>dp[k]−a[i]×b[k]+c[k]

变成
(dp[j]+c[j])(dp[k]+c[k])b[j]b[k]>a[i](dp[j]+c[j])−(dp[k]+c[k])b[j]−b[k]>a[i]

所以要求(dp[j]+c[j])(dp[k]+c[k])b[j]b[k](dp[j]+c[j])−(dp[k]+c[k])b[j]−b[k] 斜率越大越好,用单调队列维护
把上面那个b[j]b[j]当做横坐标,(dp[j]+c[j])(dp[j]+c[j])当做纵坐标。
维护的单调队列要使斜率要递减(保证前面的更大),画成图像就成了一个上凸包:
上凸包

实现

对于一个新的ii,保证b[i]最大,队列的左边为headhead,判断head与head+1的斜率,如果head+1更优,即

(dp[head+1]+c[head+1])(dp[head]+c[head])b[head+1]b[head]>a[i](dp[head+1]+c[head+1])−(dp[head]+c[head])b[head+1]−b[head]>a[i]

那么就head++;
所以dp[i]dp[i]就从head位置转移过来。
接下来把dp[i]dp[i]添加进单调队列,把队尾tail斜率比i小的全部弹出去,即
(dp[i]+c[i])(dp[tail]+c[tail])b[i]b[tail]>(dp[tail]+c[tail])(dp[tail1]+c[tail1])b[tail]b[tail1](dp[i]+c[i])−(dp[tail]+c[tail])b[i]−b[tail]>(dp[tail]+c[tail])−(dp[tail−1]+c[tail−1])b[tail]−b[tail−1]

那么就tail--;
最后把i放进tail里。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CaptainHarryChen

随便

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值