单调队列优化DP能到什么程度(今天中午进行的实验记录)
来源:互联网 发布:mac 怎么使用搜狗 编辑:程序博客网 时间:2024/04/27 14:11
想了一早上单调队列优化DP,总觉得不能优化到哪里去,又从来没有做过这种需要用单调队列优化的DP,于是自己用手模拟了一下实现过程,瞬间就明白了单调队列优化DP,这个DP的转移方程应该具有的性质。
单调队列很好理解,就是一个双向队列,队首队尾允许删除操作,队尾进行添加操作,维护整个队列的严格单调性,即队列中不存在相等的元素(这样时间常数小一点)。
那么用单调队列优化的DP应该具有怎样的性质呢?
假如我们有下面的DP转移方程:
f[i] = min( f[j] ) + a[i]
那么当 j 满足一个条件: Low[i] <= j <= Up[i] ,这里的 Low 和 Up 是关于 i 的单调函数,而且是单调递增的,为什么呢?联系经典的单调队列入门题: Sliding Window 想想就清楚了: 当我用下一个 Low[i] 的时候,Low[i] 必须大于等于 Low[i-1] ,因为队首涉及到了要出队列的操作,而队尾的元素上界: Up 也是必须具有单调递增的性质,因为再用队尾的元素的时候,涉及到添加元素的操作。如果还是不很明白,那么联系 Sliding Window 仔细想想这个单调队列删除插入的过程即可。很好想通的。
那么单调队列到底能优化到怎么样的程度呢?我们来看看下面的实验:
【实验方程】:
f[i] = min ( f[j] ) + a[i] ( 1<= j <= i-1 )
【实验过程】:
我做了个测试数据,不大,刚好有 10^5 个数。用传统的 o( n^2 ) 的算法铁定超时,二这个转移方程来看,我们可以不用单调队列优化到 o ( n ) 的复杂度:就是记录一个 1——i 的最小值 Min 每次计算 f[i] 的时候用 Min + a[i] 即可。
那么这道题总共就可以写出三个程序,时间复杂度分别是;
传统的二重循环判定: o( n^2 )
用最小值优化:o( n )
用单调队列优化:未知 (这就是这个实验要探讨的内容)
下面先给出实验程序:
1、传统的二重循环判定:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<ctime>#include<cstdlib>#define INF 0x7fffffffusing namespace std;int main(){ freopen("in.in","r",stdin); freopen("out.out","w",stdout); int n,a[100005],f[100005]; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); f[1]=a[1]; for(int i=2;i<=n;i++) { int Min=INF; for(int j=1;j<i;j++) if(Min>f[j]) Min=f[j]; f[i]=Min+a[i]; } for(int i=1;i<=n;i++) { printf("%d",f[i]); if(i==n) printf("\n"); else printf(" "); } return 0;}
用最小值优化:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<ctime>#include<cstdlib>#define INF 0x7fffffffusing namespace std;int main(){ freopen("in.in","r",stdin); freopen("out.out","w",stdout); int n,a[100005],f[100005]; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); f[1]=a[1]; int Min=f[1]; for(int i=2;i<=n;i++) { f[i]=Min+a[i]; if(f[i]<Min) Min=f[i]; } for(int i=1;i<=n;i++) { printf("%d",f[i]); if(i==n) printf("\n"); else printf(" "); } return 0;}
用单调队列优化:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<ctime>#include<cstdlib>#define INF 0x7fffffffusing namespace std;int main(){ freopen("in.in","r",stdin); freopen("out.out","w",stdout); int n,a[100005],f[100005]; int q[200000],head,tail; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); f[1]=a[1]; tail=1; head=0; q[1]=1; for(int i=2;i<=n;i++) { f[i]=f[q[1]]+a[i]; //printf("f[q[1]]=%d\n",f[q[1]]); //printf("f[%d]=%d\n",i,f[i]); while(f[i]<=f[q[tail]] && 1<=tail) tail--; q[++tail]=i; } for(int i=1;i<=n;i++) { printf("%d",f[i]); if(i==n) printf("\n"); else printf(" "); } return 0;}
程序有了,我们就可以做实验了:
我先用了一个 10^4 的数据规模来测试这三个程序,下面我们看看他们跑的时间:
从上面的数据结果可以看出,使用赤果果的的 二重循环 的话,消耗的时间几乎是使用 o( n )算法的 60 倍,然而使用 单调队列 优化的方法时,时间竟然和我预想的 “和赤果果的 o( n^2 ) 差不多”有很大的差别,竟然和 o( n ) 几乎一样了!于是不信邪的我又试了一组数据,这下我把数据规模弄到了 10^5 这个级别,下面是实验结果:
我想,到了这个地步,单调队列的时间复杂度我们不用质疑了,相当于去掉了一重循环,碉堡有木有!!
所以以后能用单调队列就尽量用单调队列吧
- 单调队列优化DP能到什么程度(今天中午进行的实验记录)
- 单调队列优化DP能到什么程度(今天中午进行的实验记录)
- 单调队列优化DP能到什么程度
- 单调队列优化的DP
- codevs 3327(dp+单调队列优化)---以此记录我的脑残经历
- 单调队列 和单调队列优化的dp
- 单调队列优化DP
- 单调队列优化DP
- dp单调队列优化
- 单调队列--优化dp
- 单调队列优化dp
- 单调队列优化DP
- 单调队列优化DP
- 单调队列优化dp
- CF487B Strip(单调队列预处理+单调队列优化dp)
- 单调队列+斜率优化的DP
- 【专辑】单调队列+斜率优化的DP
- Vijos1243----用单调队列优化的DP
- 关于xampp在centos下面链接mssql的配置
- Nginx 配置目录访问
- MFC中ODBC连接MySQL数据库查询出的中文显示为乱码的问题
- 中文分词基本算法主要分类
- dos bat批处理的魅力 批处理读取文本中的每一行 操作文件
- 单调队列优化DP能到什么程度(今天中午进行的实验记录)
- LDD3源码分析之访问控制
- c++ string操作
- EL表达式
- dll和lib(包括静态链接库和与dll同时生成的lib)
- Eclipse代码自动提示(内容辅助content assist)
- hadoop 在windows下运行时包java heap out
- Matlab基础之坐标轴操作汇总(新加网格线设置)
- 寻找凸包的graham 扫描法