动态规划的基础篇1--最大连续子序列和

上篇已经稍微介绍了什么是dp,接下来就是实战了。今天七夕节,祝愿大家有人陪伴,好好珍惜。。哎。。

给定一个数字序列A1,A2,A3,A4,A5,A6,A7,A8,A9.....An。求i,j(1<=i<=j<=n)使得Ai++++++Ai最大,输出这个最大和

样例:

-2  11 -4   13 -5 -2

显然11+(-4)+13=20为和最大的选取情况,因此最大和为20.

下面介绍动态的做法,复杂度O(n),我们会发现其实左端点的枚举是没有必要的。。

步骤1:令状态dp[i]表示以A[i]作为末尾的连续序列的最大和(这里是说A[i]必须作为连续序列的末尾)。以样例为列:序列

-2 11 -4 13 -5 2,下标分别记为0,1,2,3,4,5,那么

dp[0]=-2;

dp[1]=11

dp[2]=(11+(-4))=7;

dp[3]=(11+(-4)+13)=20

dp[4]=(11+(-4)+13+(-5))=15

dp[5]=13;

步骤2:做如下考虑:因为dp[i]要求是必须A[i]结尾的连续序列,那么只有两种情况

1.这个最大和的连续序列只有一个元素,即以A[i]开始,以A[i]结尾。

2.这个最大和连续序列有多个元素,即从前面某处A[p]开始(p<i),一直到A[i]结尾。

对于第一种情况,最大和就是A[i]本身。

对于第二种情况,最大和就是dp[i-1]+A[i];

由于只有这两种情况,于是得到转移转移方程;

dp[i]=MAX{dp[i],dp[i-1]+A[i]}

这个式子只和i与i以前的元素有关,且边界dp[0]=A[0],由此从小到大枚举i,即可得到整个dp数组,接着输出dp[0],dp[1],....dp[n-1]中的最大值即为最大连续序列的和。

-------------------------code---------------------------------------------------------

int A[maxn],dp[maxn];//从A[i]存放序列,dp[i]存放以A[i]结尾A[i]结尾的连续序列的最大和。

int main(){

int n;

scanf("%d",&n);

for(int i=0;i<n;i++)

scanf("%d",&A[i]);

//边界

dp[0]=A[0];

for(int i=1;i<n;i++)

//状态转移方程

dp[i]=max(A[i],dp[i-1]+A[i]);

//dp[i]存放以A[i]结尾的连续序列的最大和,需要遍历i得到的才是结果。

int k=0;

for(int i=1;i<n;i++){

if(dp[i]>dp[k]){

k=i;

}

}

printf("%d\n",dp[k]);

}

//废话一句,至于让我们去求这里的连续序列的话,我们已经求出下边啦,那么久知道A[i]的下标,一个While(dp[k]!=0),每次都遍历往前减。

事实上,如何设计状态和状态转移方程,才是动态规划的核心。

猜你喜欢

转载自blog.csdn.net/ZSS1753936255/article/details/81782845