动态规划相信大家都很熟悉,但也是一个难点,对于动态规划,我也写出了我的一些观点,其中我会拿(最长不下降子序列,最长公共子序列,前缀和最大值)这些比较经典的动态规划题,来表明我的观点,开始!!!!!!!!!
1794 - 最长不下降子序列(LIS)
题目描述
设有由n个不相同的整数组成的数列,记为: a(1)、a(2)、……、a(n)且a(i)<>a(j) (i<>j)。例如3,18,7,14,10,12,23,41,16,24。若存在i1<i2<i3<… < ie且有a(i1)<a(i2)<… <a(ie)则称为长度为e的不下降序列。如上例中3,18,23,24就是一个长度为4的不下降序列,同时也有3,7,10,12,16,24长度为6的不下降序列。程序要求,当原数列给出之后,求出最长的不下降序列。
输入
第一行为n,表示n个数(10<=n<=10000)
第二行n个整数,数值之间用一个空格分隔(1<=a(i)<=n)
输出
最长不下降子序列的长度
样例
输入
复制
3 1 2 3
输出
复制
3
首先,我们知道,动态规划的题目无非就是贪心 + 递推,我们要知道dp数组表达的意思,(读者可以先想一想)也就是dp[i] = 表示以a[i]为结尾的最长不下降子序列;那么,dp数组表达意思知道了,便可以开始找递推的边界,可以结合题目得知以a[1]为结尾的最长不下降子序列为1,也就是dp[1] = 1;确定这两项后,便可以开始确定状态转移方程了,我们可以去想一想,dp[i] 如何从dp[i-1]dp[i-2] dp[i-3]......推出呢?我们可以用两个循环来写,一个从2开始到n,一个从1开始到i,如果a[i] > a[j] 时,dp[i] = max(dp[i],dp[j]+1);
看代码:
dp[1] = 1;
for(int i = 2;i<=n;i++){
for(int j = 1;j<=i;j++){
if(a[i] > a[j]) dp[i] = max(dp[i],dp[j]+1);
}
}
确定转移方程后,就要确定最终的答案在哪儿,很容易看出,给dp打个擂台就行了:
int sum = INT_MIN;
for(int i = 1;i<=n;i++) sum = max(dp[i],sum);
如果你全部理解,恭喜你,你已经很厉害了,好了,时间也不早了,看完整代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[10010];
int f[10010];
int mx = -1;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
f[i]=1;
}
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
if(a[i]>=a[j])
f[i]=max(f[i],f[j]+1);
}
}
for(int i=1;i<=n;i++){
mx=max(mx,f[i]);
}
printf("%d",mx);
return 0;
}
后续我会继续更新,下次见