1.最大连续子序列和问题就是:给定一个数字序列a1,a2,a3,a4……an,求i,j(1<=i<=j<=n),使ai+……+aj的和最大,找出最大和。
比如一个序列: -1 10 -2 12 -3 -1
他的最大连续子序列和就是10+(-2)+12=20
用动态规划来处理:假设dp[i]表示以ai作为结尾的连续序列的最大和。比如:
dp[0]=-1;
dp[1]=10;
dp[2]=10+(-2)=8;
dp[3]=10+(-2)+12=20;
dp[4]=10+(-2)+12+(-3)=17;
dp[5]=10+(-2)+12+(-3)+(-1)=16;
dp[i]有两种情况:
1.dp[i]只有a[i]一个元素,这种情况dp[i]就是a[i];
2.dp[i]有多个元素。最大和就是dp[i-1]+a[i]
状态转移方程:dp[i]=max(dp[i-1]+a[i],a[i])
边界就是dp[0]=0,所以写代码的时候就从0开始依次用状态转移方程推出后面的dp[]。
2.最长不下降子序列(LIS):在一个数字序列中找到一个最长的子序列(可以不连续!),让这个序列是递增的。
这个问题要比最大连续子序列复杂一些。我们还是用dp[i]来表示以a[i]结尾的最长不下降子序列。我们用一道例题来具体说明。
这两种情况就是最大和的情况:
用图来分析做法:
我们可以自己先找出来每一个dp[],做一个分析:
我们简单分析一下前几个:
代码实现:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int a[n+1];
int dp[n+1];
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
int ans=-1;//用来找dp[]中的最大值,题目要求输出最大值
for(int i=0;i<n;i++)
{
dp[i]=1;//每一个起始的长度时候都是1
for(int j=0;j<i;j++)//在i前面找
{
if(a[i]>=a[j]&&dp[j]+1>dp[i])
{
dp[i]=dp[j]+1;
}
}
ans=max(dp[i],ans);//找到最大dp[]值
}
printf("%d",ans);
}