斜率优化dp小结
来源:互联网 发布:sql注入攻击登录 编辑:程序博客网 时间:2024/06/05 16:15
先推荐一篇博客
下文有小部分修改自:http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html
有些DP方程可以转化成DP[i]=f(i,j)+x[i]的形式,其中f[j]与i和j有关。这样的DP方程无法直接使用单调队列进行优化,所以考虑另外一中降低复杂度的方式:斜率优化!
举个例题:hdu 3507
设dp[i]表示到i的最少花费,sum[i]表示从a[1]到a[i]的数字和,有dp[i]=dp[j]+(sum[i]-sum[j])^2+M。假设k < j < i。如果在j的时候决策要比在k的时候决策好,即
dp[j]+M+(sum[i]-sum[j])^2 < dp[k]+M+(sum[i]-sum[k])^2。(求最小花费,所以优就是小于)
上不等式可以表示成yj-yk/xj-xk < sum[i],左边就是斜率g(j,k)的表示。
以下是核心操作:
假设k < j < i并且g(i,j) < g(j,k)那么j一定不属于此题(优表示小于的情况)最优解集。
①若g(i,j) < sum[p],那么显然i比j优,排除j
②若g(i,j) ≥ sum[p],那么j比i优,但是有一前提成立g(j,k) > g(i,j),所以g(j,k) > sum[p],所以k比j优,j也可以排除。
于是成功地排除了无效点,维护了一个下凸的图形
下图中左边为有效点集,右边为存在无效点的集合
具体代码实现:
定义一个单调队列。
①移动队首,找到一个斜率最大的合法的g(h+1,h),即右移到最后一个g(h+1,h)。
②用队首更新当前点(dp数组赋值)
③不断左移队尾,剔除不合法的点集。
下面是hdu 3507的AC代码:
/* dp[i]=dp[j]+M+(sum[i]-sum[j])^2 (dp[j]+sum[j]^2-(dp[k]+sum[k]^2))/(2*(sum[j]-sum[k]))<sum[i]*/#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=500002;int n,M;int sum[maxn],dp[maxn],q[maxn];inline int getY(int x,int y) { return dp[x]+sum[x]*sum[x]-dp[y]-sum[y]*sum[y];}inline int getX(int x,int y) { return (sum[x]-sum[y])<<1;}int main() { while (~scanf("%d%d",&n,&M)) { int h=0,t=0; sum[0]=dp[0]=0; for (int i=1;i<=n;++i) { scanf("%d",&sum[i]); sum[i]+=sum[i-1]; while (h<t&&getY(q[h+1],q[h])<=getX(q[h+1],q[h])*sum[i]) ++h; dp[i]=dp[q[h]]+M+(sum[i]-sum[q[h]])*(sum[i]-sum[q[h]]); while (h<t&&getY(i,q[t])*getX(q[t],q[t-1])<=getY(q[t],q[t-1])*getX(i,q[t])) --t; q[++t]=i; } printf("%d\n",dp[n]); } return 0;}
- 斜率优化dp小结
- 斜率优化dp小结
- 斜率优化dp小结
- [斜率优化小结]
- DP(斜率优化)
- 【斜率优化DP】Batch_Scheduling
- dp优化--斜率
- 斜率优化DP
- 斜率优化DP
- hdu3507斜率优化dp
- DP斜率优化总结
- hdu3480 斜率优化dp
- hdu3507 斜率优化dp
- 斜率优化DP
- 斜率优化DP 【pascal】
- 斜率优化DP
- dp 斜率优化
- 斜率优化 DP
- 代理情况下httpClient4.3 发本机404问题 (nginx + tomcat6 )
- loadrunner Web_类函数之web_url()
- 第四周项目3—单链表应用(3)
- 关于spring-oauth2的笔记
- 解决spring boot启动报错java.lang.NoClassDefFoundError: ch/qos/logback/classic/Level
- 斜率优化dp小结
- 题目49:开心的小明
- [总结]----Hive创建表格的几种方式
- 程序员把妹从入门到精通(一)
- bzoj1977 [BeiJing2010]次小生成树 Tree(kruskal+树上倍增)
- LED_1_1(流水灯)
- HDU1251(静态维护字典树模板题)
- c++设计一个分数类。要求:1.分类包含的分数运算有:连个分数的加、减、乘、除运算。
- 51NOD 1952 栈 【单调队列】