简单动态规划集(二)

来源:互联网 发布:纯软件管理的 编辑:程序博客网 时间:2024/05/21 22:22

最大子串和

题意:给定一整型数列{a1,a2...,an},找出连续非空子串{ax,ax+1,...,ay},使得该子序列的和最大,其中,1<=x<=y<=n。

对于这道题我们最简单的思路,把所有子串都找出来,然后找个最大的,如果我们真的这样做了,复杂度有点高,难度有点大了

我们这样想一下,这个子串是连续的,我们这样想一下如果,一段子串和小于0,我们回去要吗?答案是否定的,我们坚决不要

那这样就好了,我们用两个变量,max,maxsum,max记录从头开始的和,如果从头开始的和,小于0了,我们就要改头了,呵呵,maxsum记录到目前整个子串的最大和,最后我们只需输出最大值maxsum,初始化依旧是个严谨问题,我是个不够严谨的人

代码如下

 #include<stdio.h>int main(){    int t,num,i,n;    long long sum,maxsum;    scanf("%d",&t);    while(t--)    {        sum=0;        maxsum=-100;        scanf("%d",&n);        for(i=0;i<n;i++)        {            scanf("%d",&num);            sum+=num;            if(sum>maxsum)              maxsum=sum;            if(sum<0)                sum=0;        }        printf("%lld\n",maxsum);    }        return 0;}        

循环最大子段和

这也是个子串和

题意:N个整数组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续子段和的最大值。当所给的整数均为负数时和为0。

这个是个循环的,这道题由于没太卡太紧,所以可以进行一些优化就可以水了,我们把这个数字串这样储存a1……an a1……an,我们算n次n个连续序列最大子串和,找出最大值,就是这题的结果,但复杂度N^2,不是我们想要的,我们可以进行一些优化。我们这样想如果a1…………an的最大子串ai……aj,那么a1……an a2……a(n+1)……ak……a(n+k)(k<=i)这些子串和是否大于ai……aj和ai……a(i+n)呢,

如果大于

ax……ay大于他们如果y>i,由于那么那么可以继续往后加,一直到aj

如果y<i不符合题意

所以下次求最大值可以从i开始,可以优化一部分。

代码如下

#include<stdio.h>#define N    100005__int64 a[N];int main(){    int n,i,j;    __int64 sum,max,maxsum,p,q;    scanf("%d",&n);    for(i=0;i<n;i++)    {scanf("%I64d",&a[i]);a[i+n]=a[i];}    p=0;q=0;    maxsum=0;    for(i=0;i<n;i=++p)    {        sum=0;max=0;        p=i;q=i;        for(j=i;j<i+n;j++)        {            max+=a[j];            if(max<0){max=0;q=j;}            if(max>sum){sum=max;p=q;}         }        if(sum>maxsum)maxsum=sum;    }    printf("%I64d\n",maxsum);}
我们又想了,如果数据特殊处理化了,我们不就死定了,能不能把这个算法,真正优化到n呢,答案也是肯定的,

方法是求出这段数字,最大和和最小和,还有总和,输出(总和减去最小和)和(最大和)他两个之间的最大值


#include <stdio.h>int main() {  int n, i, a;  long long max = 0, min = 0, s1 = 0, s2 = 0, sum = 0;  scanf( "%d", &n );  for( i = 0; i < n; ++i ) {    scanf( "%d", &a );    s1 = a + ( s1 > 0 ? s1 : 0 );    if( s1 > max ) max = s1;    s2 = a + ( s2 < 0 ? s2 : 0 );    if( s2 < min )  min = s2;    sum += a;  }  printf( "%I64d\n", max > ( sum - min ) ? max : ( sum - min ) );  return 0;}

这个问题到这,也就有了结束了,结束了吗,没给出证明,就能说这个算法正确吗,这是不严谨的,

我们这样想一下,最大子串和要么由这个序列中组成要么有这个序列的头部分和尾部分组成,第一种情况我们可以直接求出,第二种情况除了这段子序列最小和(小于0),其余数组成序列,就是头尾相连的最大和序列(当然这个序列可能只包含这个序列头或尾,包括我们说的那种情况),呵呵

原创粉丝点击