动态规划基础题:低价购买(最长下降子序列)
来源:互联网 发布:淘宝闲鱼拍卖 编辑:程序博客网 时间:2024/05/22 13:36
题目描述
“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价(2^16范围内的正整数),你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。
这里是某支股票的价格清单:
日期 1 2 3 4 5 6 7 8 9 10 11 12
价格 68 69 54 64 68 64 70 67 78 62 98 87
最优秀的投资者可以购买最多4次股票,可行方案中的一种是:
日期 2 5 6 10
价格 69 68 64 62
输入输出格式
输入格式:
第1行: N (1 <= N <= 5000),股票发行天数
第2行: N个数,是每天的股票价格。
输出格式:
输出文件仅一行包含两个数:最大购买次数和拥有最大购买次数的方案数(<=2^31)当二种方案“看起来一样”时(就是说它们构成的价格队列一样的时候),这2种方案被认为是相同的。
看完试题就应该能明白,这是一道典型的最长下降子序列问题。最长下降子序列是一个典型的O(n^2)动态规划问题。本文将阐述如何求出最长下降子序列长度、统计个数以及快速去重。
长度求解
其实就是一个很简单的转移问题。对于第i个元素,它的最长下降子序列长度总是由前i-1个元素转移得来的。具体而言,它的转移总来源于前I-1个元素中满足a[i]>a[j] (j∈[1,i-1])的最长下降子序列长度最大的元素。听起来很绕口,我们用转移方程来表示:
f[i]=f[j]+1 (j∈[1,i-1]且j∈N*, i∈[1,n], a[i]
#include <cstdio>#define max(x,y) x>y?x:yusing namespace std;int n,a[5005],f[5005];int main(){ int i,j,ans=0; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=1; for(i=2,j=1;i<=n;j=j==i-1?1:j+1,i+=(j==1)) if(a[i]<a[j]&&f[j]>=f[i]) f[i]=f[j]+1; for(i=1;i<=n;i++) ans=max(ans,f[i]); printf("%d",ans); return 0;}
统计个数
如何进行个数统计?看起来这个问题很简单,只要开一个数组,在转移的时候不断修改就行了。事实上,真正写起来,要做的修改还是挺多的。
#include <cstdio>#define max(x,y) x>y?x:yusing namespace std;int n,a[5005],f[5005],c[5005];int main(){ int i,j,ans=0; scanf("%d",&n);a[n+1]=-1; for(i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=1,c[i]=1; for(i=2,j=1;i<=n+1;j=j==i-1?1:j+1,i+=(j==1)){ if(a[i]<a[j]&&f[i]==f[j]+1) c[i]+=c[j]; if(a[i]<a[j]&&f[j]>=f[i]) f[i]=f[j]+1,c[i]=c[j]; } printf("%d %d\n",f[n+1]-1,c[n+1]); return 0;}
输入
4
4 4 2 1
输出
3 2
哈!统计成功了……慢着,好像有哪里不对……哪里来的两个序列?不都是4 4 2 1吗?
快速去重
刚刚我们看到,会有重复的序列来影响计数,也就是题目描述的“看起来一样”。因此,我们需要一种去重方法。
有人说:去重简单!把所有的方案记录下来,然后挨个比较不就好了?
行!只是……真的很慢。
那么我们不妨换一种思维……由于重复只会影响计数数组c[i],并且重复现象的作用一定是产生在c[j]到c[i]的转移过程中的。不如,我们从源头出发,来阻止这个问题的发生。
在每一次进行计数后,开辟一次O(i)的校验,当且仅当存在v[i]==v[j],f[i]==f[j]时,将c[i]强制设置为0.
#include <cstdio>#define max(x,y) x>y?x:yusing namespace std;int n,a[5005],f[5005],c[5005];int main(){ int i,j,ans=0; scanf("%d",&n);a[n+1]=-1; for(i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=1,c[i]=1; for(i=2,j=1;i<=n+1;j=j==i-1?1:j+1,i+=(j==1)){ if(a[i]<a[j]&&f[i]==f[j]+1) c[i]+=c[j]; else if(a[j]==a[i]&&f[i]==f[j]) c[j]=0; if(a[i]<a[j]&&f[j]>=f[i]) f[i]=f[j]+1,c[i]=c[j]; } printf("%d %d\n",f[n+1]-1,c[n+1]); return 0;}
- 动态规划基础题:低价购买(最长下降子序列)
- Codevs 4748 低价购买 最长下降子序列方案数
- wust oj 1891 低价购买(最长下降子序列+方案数)【模板】
- 最长不下降子序列(动态规划)
- 最长不下降子序列 动态规划
- 最长不下降子序列(动态规划:LIS)
- 【Algothrim】动态规划实例(最长不下降子序列)
- 洛谷Oj-低价购买-最长下降子序列 +最佳方案数统计
- 低价购买(动态规划)
- 低价购买(动态规划)
- 蓝桥杯 拦截导弹 动态规划(最长下降子序列+最长上升子序列)
- 动态规划之——最长不下降子序列
- (2)最长不下降子序列问题____动态规划
- 动态规划之最长不下降子序列
- hdu1160 FatMouse's Speed 最长下降子序列 动态规划
- 【动态规划】【二分】【最长下降子序列】XMU 1041 Sequence
- 动态规划——求最长下降/上升子序列
- HDU1069_Monkey and Banana_动态规划 求 最长下降子序列
- 原码,反码,补码
- Epoll模型详解
- 405. Convert a Number to Hexadecimal
- JAVA对象锁与类锁
- 1-保护模式
- 动态规划基础题:低价购买(最长下降子序列)
- Nginx和Tomcat配合使用
- Spring框架核心技术--IOC容器
- stm32f芯片唯一ID的加密
- STL综合案例-模拟演讲比赛
- Hello World
- 我读过最好的Epoll模型讲解
- 抽象工厂模式范例A
- CyclicBarrier 栅栏