模型化理解单调队列优化和斜率优化DP
2016-06-30 20:32
453 查看
设A(x),B(x),C(x),D(x)为仅关于x的一元函数
dp[i]=A(i)+B(j)中的最小/大值 (i-k<=j<i,k为常数)
dp[i]=dp[j]+(i-j)*w // 选自hdu3401
A(i)=i*w
B(j)=dp[j]-j*w
维护B(j)的最大合法值进行转移即可
建立一层循环i=1~n
每次先用i-k更新单调队列队头位置,然后用单调队列中的最值点更新dp[i],最后将B(i)加入单调队列
dp[i]=-A(i)*B(j)+C(i)+D(j) 中的最小值,j<i,A(x),B(x)为增函数
dp[i]=-A(i)*B(j)+C(i)+D(j) 中的最大值,j<i,A(x)为减函数,B(x)为增函数
dp[i]=dp[j]+(s[i]-s[j])^2 /*此处指平方*/ +M // 选自HDU3507
A(i)=s[i]
B(j)=s[j]*2
C(i)=s[i]*s[i]+M
D(j)=s[j]*s[j]+dp[j]
以取最小值为例
当从j>k,j转移到i比从k转移到i更优时有
-A(i)*B(j)+C(i)+D(j)<-A(i)*B(k)+C(i)+D(k)
变形得[D(j)-D(k)]/[B(j)-B(k)]<A(i)
设g(j,k)=[D(j)-D(k)]/[B(j)-B(k)]
可以证明,对于a<b<c,若g(c,b)<g(b,a),b永远不可能作为转移的最优决策,因为当g(c,b)<A(i),c比b优,当g(b,a)>g(c,b)>A(i),a比b优,那么b点可以删除
把D(j)当作y,B(j)当作x,那么g(j,k)就是连接j,k两点的线段斜率,最后维护出的队列为一个下凸包,如下图
当转移到i时我们选择前面的斜率小于A(i)后面斜率大于A(i)的点转移,顺便把队头定义到这个位置。
设找到点j,这样可以保证对于任意k>j有g(k,j)>A(i),j更优;对于任意k<j有g(j,k)<A(i),j还是更优
我们需要维护一个队列,使得其中元素两两之间的斜率递增
因为A(i)单增,所以可以定期删除队头元素,每次转移从队头取然后将新的点加入队尾并维护斜率单增
单调队列DP
DP转移方程需要满足的条件:
dp[i]=A(i)+B(j)中的最小/大值 (i-k<=j<i,k为常数)
例子:
dp[i]=dp[j]+(i-j)*w // 选自hdu3401A(i)=i*w
B(j)=dp[j]-j*w
分析:
维护B(j)的最大合法值进行转移即可
实现:
建立一层循环i=1~n每次先用i-k更新单调队列队头位置,然后用单调队列中的最值点更新dp[i],最后将B(i)加入单调队列
struct dddl//单调队列 { int q[maxn]; int p[maxn]; int h,t; void clear(){h=1,t=0;} void eliminate(int minp){while(p[h]<minp&&h<=t) h++;} void insert(int pos,int val) { while(q[t]<=val&&h<=t) t--; q[++t]=val; p[t]=pos; } int top(){return q[h];} }que; int dp[maxn]; void dynamic_programming()//以取最大值为例 { que.clear(); dp[0]=0; que.insert(0,0);//预处理,具体函数值视情况而定 for(int i=1;i<=n;i++) { que.eliminate(i-k); dp[i]=que.top()+A(i); que.insert(i,B(i)); } }
斜率优化DP
DP转移方程需要满足的条件:
dp[i]=-A(i)*B(j)+C(i)+D(j) 中的最小值,j<i,A(x),B(x)为增函数dp[i]=-A(i)*B(j)+C(i)+D(j) 中的最大值,j<i,A(x)为减函数,B(x)为增函数
例子:
dp[i]=dp[j]+(s[i]-s[j])^2 /*此处指平方*/ +M // 选自HDU3507A(i)=s[i]
B(j)=s[j]*2
C(i)=s[i]*s[i]+M
D(j)=s[j]*s[j]+dp[j]
分析:
以取最小值为例当从j>k,j转移到i比从k转移到i更优时有
-A(i)*B(j)+C(i)+D(j)<-A(i)*B(k)+C(i)+D(k)
变形得[D(j)-D(k)]/[B(j)-B(k)]<A(i)
设g(j,k)=[D(j)-D(k)]/[B(j)-B(k)]
可以证明,对于a<b<c,若g(c,b)<g(b,a),b永远不可能作为转移的最优决策,因为当g(c,b)<A(i),c比b优,当g(b,a)>g(c,b)>A(i),a比b优,那么b点可以删除
把D(j)当作y,B(j)当作x,那么g(j,k)就是连接j,k两点的线段斜率,最后维护出的队列为一个下凸包,如下图
当转移到i时我们选择前面的斜率小于A(i)后面斜率大于A(i)的点转移,顺便把队头定义到这个位置。
设找到点j,这样可以保证对于任意k>j有g(k,j)>A(i),j更优;对于任意k<j有g(j,k)<A(i),j还是更优
实现:
我们需要维护一个队列,使得其中元素两两之间的斜率递增因为A(i)单增,所以可以定期删除队头元素,每次转移从队头取然后将新的点加入队尾并维护斜率单增
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int n,m; long long dp[maxn]; int que[maxn]; long long ky(int a,int b) { return D(a)-D(b); } long long kx(int a,int b) { return B(a)-B(b); } void dynamic_programming()//以取最小值为例 { dp[0]=0;//预处理,具体函数值视情况而定 que[++t]=0; for(int i=1;i<=n;i++) { while(t>h&&ky(que[h+1],que[h])<=kx(que[h+1],que[h])*A[i]) h++; //一定要写成相乘形式,否则会引起除以0,精度低等一系列问题 dp[i]=A(i)*B(que[h])+C(i)+D(que[h]); while(t>h&&ky(i,que[t])*kx(que[t],que[t-1])<=ky(que[t],que[t-1])*kx(i,que[t])) t--; que[++t]=i; } }
相关文章推荐
- WHOIS类的修改版
- 详解Android应用中屏幕尺寸的获取及dp和px值的转换
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- LFC1.0.0 版本发布
- Android dpi,dip,dp的概念以及屏幕适配
- Android px、dp、sp之间相互转换
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- android中像素单位dp、px、pt、sp的比较
- Android对px和dip进行尺寸转换的方法
- Android根据分辨率进行单位转换-(dp,sp转像素px)
- android 尺寸 dp,sp,px,dip,pt详解
- DP问题各种模型的状态转移方程
- POJ-1695-Magazine Delivery-dp
- nyoj-1216-整理图书-dp
- TYVJ1193 括号序列解题报告
- 对DP的一点感想
- TYVJ上一些DP的解题报告
- soj1005. Roll Playing Games