1D1D动态规划优化
1D1D动态规划优化
1D/1D 动态规划优化初步
所谓1D/1D 动态规划,指的是状态数为O(n),每一个状态决策量为O(n)的动态规划方程。
直接求解的时间复杂度为O(n2),但是,绝大多数这样的方程通过合理的组织与优化都是可
以优化到O(nlogn)乃至O(n)的时间复杂度的。这里就想讲一讲我对一些比较初步的经典的
优化方法的认识。
本文中不想进行过多的证明与推导,主要想说明经典模型的建立、转化与求解方法。
由于本人认识与水平相当有限,如果出现什么错误与疏漏,还请大牛多多指正。另外,也
希望大牛们更多地向我们介绍一下有关动态规划优化的更深入的东西。
本文中使用两种方式表示一个函数:f(x)与f[x],用方括号表示的函数值可以在规划之前
全部算出(常量),而用圆括号表示的函数值必须在规划过程中计算得到(变量)。无论是什
么函数值一经确定,在以后的计算中就不会更改。
我们总是沿着“f(x)的最优决策是什么”这个思路进行思考,下面我们换一个角度,
思考对于一个已经计算出来的状态f(j),“f(j)能够更新的状态有哪些”。这样,每一步过程中
某些状态的决策可能不是最优的,但是当算法结束的时候所有状态对应的决策一定是最优
的。
一开始,只有f(1)的函数值被计算出来,于是所有状态的当前最优决策都是1。
111111111111111111111111111111111111111111111111111111111111111
现在,显然f(2)的值已经确定了:它的最有决策只能是1。我们用决策2 来更新这个决策
表。由于决策单调性,我们知道新的决策表只能有这样的形式:
111111111111111111111111111111222222222222222222222222222222
这意味着我们可以使用二分法来查找“转折点”,因为如果在一个点x 上,如果决策2 更
好,则所有比x 大的状态都是决策2 更好;如果x 上决策1 更好,则所有比x 小的状态都是
决策1 更好。
现在决策1 和决策2 都已经更新完毕,则f(3)业已确定,现在用决策3 来更新所有状态。
根据决策单调性,现在的决策表只能有以下2 种类型:
11111111111111111111111111111111122222222222222222233333333333
1111111111111111111111111333333333333333333333333333333333333
而这样的决策表示绝对不会出现的:
111111111111333333333333333333322222222222222222222222222222,不可能。
那么,我们的更新算法就是:
1、 考察决策2 的区间[b,e]的b 点上是否决策3 更优,如果是,则全部抛弃决策2,将此
区间划归决策3;如果否,则在决策2 的区间[b,e]中二分查找转折点。
2、 如果第1 问的回答是“是”,则用同样的方法考察决策1。
推演到这一步,相信决策单调性的实现算法已经明了了:使用一个栈来维护数据,占中的
每一个元素保存一个决策的起始位置与终了位置,显然这些位置相互连接且依次递增。当插
入一个新的决策时,从后到前扫描栈,对于每一个老决策来说,做这样两件事:
1、 如果在老决策的起点处还是新决策更好,则退栈,全额抛弃老决策,将其区间合并至
新决策中,继续扫描下一个决策。
2、 如果在老决策的起点处是老决策好,则转折点必然在这个老决策的区间中;二分查找
之,然后新决策进栈,结束。
由于一个决策出栈之后再也不会进入,所以均摊时间为O(1),但是由于二分查找的存在,
所以整个算法的时间复杂度为O(nlogn)。
noi2009a 诗人小G对应的1D1D动态规划优化分析
//不要去洛谷上面提交,洛谷的这题数据有问题,去codeVs
#include<cstdio>
#include<cstring>
#define ll long double
//node[i]代表i,里面的l代表决策的作用起点,r代表决策的作用终点,p是决策的值
struct node{int l,r,p;}q[];
#define MAX 1000000000000000000LL
#define N 100100
ll sum[N],f[N];
int n,l,p,T;
char ch[];
//求|y|^p的函数
ll pow(ll y){
if(y<)y=-y;
ll ans=;
for (int i=;i<=p;i++) ans*=y;
return ans;
}
//计算不协调度
ll calc(int x,int y){
return f[x]+pow(sum[y]-sum[x]+(y-x-)-l);
}
//二分查找找决策转折点
//node表示老决策点,x表示新决策点的值
//这个函数就是在老的决策点的范围中寻找新的决策点的值
int find(node t,int x){
int l=t.l,r=t.r;
while(l<=r){//当头小于等于尾,也就是还有数可以查找的时候
//mid=(头+尾)/2
int mid=(l+r)>>;
//小于的情况,也就是新的决策点更有,我们就要一直往前继续扩展新的决策点的起点,
//直到老决策点比较好的时候
if (calc(x,mid)<=calc(t.p,mid)) r=mid-;
//大于的情况,也就老决策点比较好的时候,我们往后搜索新决策点的作用域的起点
else l=mid+;
}
//返回头
return l;
} void dp(){
//用数组模拟栈,头置为1,尾置为0
int head=,tail=;
//将第一个决策入栈,决策1的起点为0,终点为n,决策的初始值置为0,因为初始决策就是0
q[++tail]=(node){,n,};
//求取f[i]
for (int i=;i<=n;i++){
//如果栈头结点上的决策作用终点小于i,说明这个决策已经无法对i进行作用,所以我们要换新的决策
//head<=tail栈的头小于等于尾,说明栈里面还有新的决策,那就换上新的决策
//因为head++,所以此时头节点是指向新的决策
if(q[head].r<i&&head<=tail) head++;
//用新的可以作用i位置的决策来计算f[i]的值,这样计算出来的f[i]的值就是最优值
f[i]=calc(q[head].p,i);
//calc(i,n)表示通过值为i的决策去计算f[n]的值
//calc(q[tail].p,n)表示通过旧决策q[tail].p去计算f[n]的值
//calc(i,n)<=calc(q[tail].p,n)表示值为i的决策优于老决策,我们才进行下一步
//不然,如果老决策更好,我们根部用不着换决策 //每一个被计算出来的f[i],都会使i成为新的决策,因为我有了f[i]的值,
//所以我可以用f[i]的值帮助计算别的f[k](k>i),所以f[i]就是新的决策 /*
比如说我们的样例1中,当i==3时,我们通过 q[head].p=2这个决策把f[3]算出来了
比如说这里的n是4,如果calc(3,4)<=calc(2,4),那说明值为3的这个新决策更好,
我们就要在决策2的作用区间里面找出决策3的作用区间
*/ //如果新决策更好,找出新决策的作用范围
//确定新决策点的终点
if (calc(i,n)<=calc(q[tail].p,n)){
//如果栈的头小于等于尾,head<=tail,说明栈里有元素
//calc(q[tail].p,q[tail].l)表示用旧决策点决策值来决策旧决策点的起点
//calc(i,q[tail].l)用新决策点来决策旧决策点的起点
//如果后者小于前者,说明新决更好,那就要在更广阔的范围里面去寻找新决策点的决策范围
//换句话说,就是当新决策点的作用范围覆盖了老决策点,我们要到比旧决策点更老点决策点里面寻找新决策点的作用方位
while(head<=tail&&calc(q[tail].p,q[tail].l)>=calc(i,q[tail].l)) tail--;
//head>tail说明栈已经为空了,就是说现在新决策点最好,所以把新决策点入栈
if(head>tail)q[++tail]=(node){i,n,i};
else{
//否则,我们就要去寻找新决策点的作用范围
//x返回新决策点范围的起点
int x=find(q[tail],i);
//旧决策点的尾部置为x-1
q[tail].r=x-;
//将新决策点入栈
q[++tail]=(node){x,n,i};
}
}
}
} int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&l,&p);
for (int i=;i<=n;i++) scanf("%s",ch),sum[i]=sum[i-]+strlen(ch);
dp();
if(f[n]>MAX)
puts("Too hard to arrange");
else
printf("%lld\n",(long long)f[n]);
puts("--------------------");
}
return ;
}
1D1D动态规划优化的更多相关文章
- 1D1D动态规划优化初步
再学习一下动态规划的基本优化方法- 首先这篇文章应该大家都看过吧-没看过的自行百度 关于实现的思路文章里都给好了-这篇就主要给一点题目啥的 (P.S. 电脑重装了,如果博客发出来有一些奇怪的问题不要在 ...
- 【bzoj2216】[Poi2011]Lightning Conductor 1D1D动态规划优化
Description 已知一个长度为n的序列a1,a2,…,an.对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p – sqrt(abs ...
- OI动态规划&&优化 简单学习笔记
持续更新!! DP的难点主要分为两类,一类以状态设计为难点,一类以转移的优化为难点. DP的类型 序列DP [例题]BZOJ2298 problem a 数位DP 常用来统计或者查找一个区间满足条件的 ...
- 《挑战程序设计竞赛》2.3 动态规划-优化递推 POJ1742 3046 3181
POJ1742 http://poj.org/problem?id=1742 题意 有n种面额的硬币,面额个数分别为Ai.Ci,求最多能搭配出几种不超过m的金额? 思路 据说这是传说中的男人8题呢,对 ...
- 动态规划优化算法——wqs二分 and 折线优化
坑先扔着,督促自己以后来补!!!
- 队列优化和斜率优化的dp
可以用队列优化或斜率优化的dp这一类的问题为 1D/1D一类问题 即状态数是O(n),决策数也是O(n) 单调队列优化 我们来看这样一个问题:一个含有n项的数列(n<=2000000),求出每一 ...
- DP的优化总结
一.预备知识 \(tD/eD\) 问题:状态 t 维,决策 e 维.时间复杂度\(O(n^{e+t})\). 四边形不等式: 称代价函数 w 满足凸四边形不等式,当:\(w(a,c)+w(b,d)\l ...
- 【BZOJ】1096: [ZJOI2007]仓库建设(dp+斜率优化)
http://www.lydsy.com/JudgeOnline/problem.php?id=1096 首先得到dp方程(我竟然自己都每推出了QAQ)$$d[i]=min\{d[j]+cost(j+ ...
- bzoj1563
P<=10一开始是吓死我了 后来想到这就是一个经典的决策单调性解决1d1d动态规划的题目 像决策单调性完全可以打表找规律,这里有一篇严谨的证明https://www.byvoid.com/blo ...
随机推荐
- Cannot resolve symbol R
最近遇到一个奇怪的问题,在Android build 完版本后,将app 删除后,直接出现 Cannot resolve symbol R , Clean. ReBuild 等试过都没效果. 最终解决 ...
- IIS添加映射配置
这种问题主要出现在使用应用程序级别的地址重写.如果你将一个动态的地址重写成虚拟的其它扩展名或者不带扩展名的地址,通常在IIS5.1和II6.0中,访问这样一个实际不存在的地址,首先会被Web服务器返回 ...
- (转)学习淘淘商城第二十二课(KindEditor富文本编辑器的使用)
http://blog.csdn.net/u012453843/article/details/70184155 上节课我们一起学习了怎样解决KindEditor富文本编辑器上传图片的浏览器兼容性问题 ...
- struts2_validate表单验证
使用代码实现 验证功能 (也就是重写ActionSupport中的validate()方法) 在validate方法中进行编写我们需要的验证功能 这里需要提几点的就是: 1.当我们需要对action中 ...
- abstract class和interface 抽象类与接口类的区别
抽象类与类型定义相关: 接口类与行为规范相关: 接口类不是类型. 抽象类:是不完整的类,函数实现未定义:可以继承,不可以实例化. 接口类:接口类不是类:是类间交互的规范:不能继承.不能实例化,只能实现 ...
- ubuntu.16.04 安装.net core记录
jack@ubuntu:~$ sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotne ...
- Java数组数据类型
Java数组数据类型 数组是多个相同类型的数据的组合,数组中的元素可以是任何类型的数据: 一维数组 package com.ahabest.array; public class ArratTest ...
- RESTful API 学习【第1篇】
一. 什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角 ...
- C++中的各种进制转换函数汇总及学习
一.指定格式输出 1.C中指定格式输出 printf(); //按八进制格式输出,保留5位高位补零 printf(); //按十进制格式输出,保留3位高位补零 printf(); //按十六进制格式输 ...
- 49.ardinality算法之优化内存开销以及HLL算法
主要知识点 precision_threshold参数的理解 HLL算法优化(hash) cardinality,count(distinct),5%的错误率,性能在100ms左右 ...