题目描述:求一个序列中连续子序列和的最大值(如果全为负,则输出0)
分析思路:简单的DP题
1.分析:最开始想到的是分治,分治的复杂度是 O[n*lb(n)][姑且把lb当做以2为底的对数],由于分治的时候遇到连接处的处理问题,一不小心就想到了原来这是DP题。
2.状态转移方程:
(1)sum[i]=max{sum[i-1]+base[i],base[i]};
(2)如果sum[i]<0,sum[i]=0;
3.关于状态转移方程的分析:
(1)sum[i]表示前i个元素中,包含i的最大子序列和;
(2)base[i]表示第i个元素;
(3)sum[i]的值直接受到base[i]和sum[i-1]的影响(至于为什么不受sum[i-2],sum[i-3]...的影响,这就是DP的魅力了。很好想到的,只是不好解释。简单地说,其实sum[i-2],sum[i-3]...的影响已经在计算sum[i-1],sum[i-2]...时考虑了)
(4)如果sumi[i]为负,为了保证”如果全为负,则输出0“,需要将sum[i]初始化为0;
(5)算法复杂度:O(n)
(6)实例分析:
代码分析:
1 /* 2 3 Title : The Bigest sblist sum 4 5 Date : 2015/3/11 6 7 Writed by yanglingwell 8 9 Class: Software 1403 10 11 */ 12 13 #include<stdio.h> 14 15 int max(int a,int b) 16 { 17 18 return a>b?a:b; 19 20 } 21 22 int main() 23 { 24 25 int T;//T组测试数据 26 27 scanf("%d",&T); 28 29 while(T--){ 30 31 int i; 32 int N;//每组数据含有N个数据的序列 33 int maxsum=0;//记录最大子序列和 34 int base[1000]={0};//记录每组的数据 35 int sum[1000]={0};//sum[i]表示前i个元素中,包含i的最大子序列和 36 37 scanf("%d",&N); 38 39 for(i=1;i<=N;i++) 40 { 41 42 scanf("%d",&base[i]); 43 44 } 45 46 for(i=1;i<=N;i++) 47 { 48 49 sum[i]=max(sum[i-1]+base[i],sum[i]);//主要状态转移方程 50 51 if(maxsum<sum[i]) maxsum=sum[i]; 52 53 if(sum[i]<0) sum[i]=0;//当sum[i]小于0时前面的数据会是后面的负担,所以应该把sum初始化为0; 54 55 } 56 57 printf("%d\n",maxsum); 58 59 } 60 61 return 0; 62 63 }
测试数据:
题外话:实在是因为这两天在研究DP问题和记忆化搜索,所以才会水过这道题。
DP真的很有意思。
时间: 2024-10-07 05:07:04