题目阅览
A同学的学习成绩十分不稳定,于是老师对他说:“只要你连续4天成绩有进步,那我就奖励给你一朵小红花。”可是这对于A同学太困难了。于是,老师对他放宽了要求:“只要你有4天成绩是递增的,我就奖励你一朵小红花。”即只要对于第i、j、k、l四天,满足i<j<k<l并且对于成绩wi<wj<wk<wl,那么就可以得到一朵小红花的奖励。现让你求出,A同学可以得到多少朵小红花。
输入格式
第一行一个整数n,表示总共有n天。第二行n个数,表示每天的成绩wi。
输出格式
一个数,表示总共可以得到多少朵小红花。
样例输入1
6
1 3 2 3 4 5
样例输出1
6
样例说明
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
思路简介
这道题的主要思路是动态规划问题,下面我想先来记录一些关于动态规划的知识,大佬可略过^ _ ^
动态规划思想与性质
首先,动态规划核心思想是把原问题分解成子问题进行求解,也就是分治的思想。
那么什么问题适合用动态规划呢?我们通过一个现实中的例子,来理解这个问题。大家可能在公司里面都有一定的组织架构,可能有高级经理、经理、总监、组长然后才是小开发,今天我们通过这个例子,来讲讲什么问题适合使用动态规划。又到了一年一度的考核季,公司要挑选出三个最优秀的员工。一般高级经理会跟手下的经理说,你去把你们那边最优秀的3个人报给我,经理又跟总监说你把你们那边最优秀的人报给我,经理又跟组长说,你把你们组最优秀的三个人报给我,这个其实就动态规划的思想!
首先是重叠子问题,不同的问题,可能都要求1个相同问题的解。假如A经理想知道他下面最优秀的人是谁,他必须知道X,Y,Z,O,P组最优秀的人是谁, 甲总监想知道自己下面最优秀的人是谁,也要去知道X,Y,Z组里面最优秀的人是谁?这就有问题重叠了,两个人都需要了解X,Y,Z三个小组最优秀的人。
其次是最优子结构,最优解肯定是有最优的子解转移推导而来,子解必定也是子问题的最优解。甲总监下面最优秀的3个人肯定是从X,Y,Z提交上来的3份名单中选择最优秀的三个人。例如Q哥是X组长下面的第5名,那么他肯定不可能是甲总监下面最优秀的三个。
第三是无后效性,这个问题可能比较难理解,也就是求出来的子问题并不会因为后面求出来的改变。我们可以理解为,X组长挑选出三个人,即便到了高级经理选出大部门最优秀的三个人,对于X组来说,最优秀的还是这3个人,不会发生改变。
求解过程
动态规划问题,大致可以通过以下四部进行解决。
1.划分状态,即划分子问题,例如上面的例子,我们可以认为每个组下面、每个部门、每个中心下面最优秀的3个人,都是全公司最优秀的3个人的子问题
2.状态表示,即如何让计算机理解子问题。上述例子,我们可以实用f[i][3]表示第i个人,他手下最优秀的3个人是谁。
3.状态转移,即父问题是如何由子问题推导出来的。上述例子,每个人大Leader下面最优秀的人等于他下面的小Leader中最优秀的人中最优秀的几个。
4.确定边界,确定初始状态是什么?最小的子问题?最终状态又是什么。例如上述问题,最小的子问题就是每个小组长下面最优秀的人,最终状态是整个企业,初始状态为每个领导下面都没有最优名单,但是小组长下面拥有每个人的评分
以上参考此网址:动态规划算法入门
天天向上实现代码
#include <iostream>
#include <vector>
using namespace std;
long long dp[2001][2001];
int main(){
int n;
cin>>n;
vector<int> numberLists;
for(int i=0;i<n;i++){
int temp;
cin>>temp;
numberLists.push_back(temp);
}
long long flower = 0;
for(int i=n-1;i>=0;i--){
dp[i][1]=1;
for(int j=i+1;j<n;j++){
//如果后边数字大于前面数字
if(numberLists[j]>numberLists[i]){
int k=2;
while(1){
//个数为0时结束循环
if(dp[j][k-1]==0)
break;
//否则继续循环
dp[i][k]=dp[i][k]+dp[j][k-1];
k++;
}
}
}
}
for(int i=n-1;i>=0;i--){
flower+=dp[i][4];
}
cout<<flower<<endl;
return 0;
}
代码实现步骤
以下面例子为题介绍:
输入
6
1 3 2 3 4 5
能得到小红花的情况
1 3 4 5
1 2 3 4
1 2 3 5
1 2 4 5
1 3 4 5
2 3 4 5
代码实现思路
首先,我们首先将这些数据存在一个可变数组中,在此使用dp[i][j]表示动态规划,他表示从第i个数开始,所有递增序列长度为j的个数,本题要求四个递增的序列个数,即求dp[i][4]的结果,由此我们便得到小红花的个数。
假设以给定序列 1 3 2 3 4 5为例:
dp[1][2]表示从第二个数3开始,一直到最后的数据5,递增序列长度为2的个数,我们可以观察到,满足这样的序列有2个,后面的34 和 35都符合条件,即。所以dp[1][2]=2;
有了上述的定义,我们就可以得出以下递推公式
dp[i][j]= ∑dp[k][j-1] (k>i,a[k]>a[i])
即接下来就要确定边界条件以及终止条件了,容易知道 dp[n-1][1]是边界条件,值为1,而假设dp[i][j]=0,即没有这样的数据符合要求,即为终止条件。
这样依次计算求出dp[i][4],求和相加得出结果,求解步骤如下所示:
运行截图