DP专题3 POJ 2593 Max Sequence

传送门:http://poj.org/problem?id=2593

                                                                                Max Sequence

Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 13282 Accepted: 5540

Description

Give you N integers a1, a2 ... aN (|ai| <=1000, 1 <= i <= N).

You should output S.

Input

The input will consist of several test cases. For each test case, one integer N (2 <= N <= 100000) is given in the first line. Second line contains N integers. The input is terminated by a single line with N = 0.

Output

For each test of the input, print a line containing S.

Sample Input

5
-5 9 -5 11 20
0

Sample Output

40

Source

 

 

    题目大意: 取数组中分开的连续两段,使其总和最大。

    分析:这题和DP专题2中的题目其实差不多,只是这里改成了求两段,很清晰的感受就是,把数组a1 a2 ……an,从a1和a2之间、a2和a3之间,一直到an-1和an之间,分别斩断,然后求解这两段中的最大值再相加,最后遍历这n-1个结果,去最大值。BUT,超时了。。。

    超时代码如下:

   

#include <stdio.h>
#include <stdlib.h>
int input[100010];
int s[100010];
int temp[100010];
int dp(int i , int j)
{
    int m , flag ;
    if(i == j)
    return input[i];
    //m = i + 1;
    temp[i] = input[i];
    for(m = i+1 ; m <= j ; m ++)
    {
        if(temp[m-1]>0)
          temp[m] = temp[m-1] + input[m];
        else
          temp[m] = input[m];
    }
    flag = temp[i];
    for(m = i + 1 ; m <= j ; m ++)
      if(temp[m]>flag) flag = temp[m];
    return flag;
}
int main()
{
    int n , i;
    int sl,sr,flag;
    while(scanf("%d",&n),n)
    {
        for(i = 1 ; i <= n ; i ++)
          scanf("%d",&input[i]);
        memset(temp,0,sizeof(temp));
        for(i = 1 ; i <= n - 1 ; i ++)
        {
            sl = dp(1,i);
            sr = dp(i+1,n);
            s[i] = sl + sr ;
        }
        flag = s[1];
        for(i = 1 ; i <= n - 1 ; i++)
          if(s[i]>flag) flag = s[i];
        printf("%d\n",flag);
    }
    return 0;
}


    回过头来看,确实,o(n^2)的复杂度,而数据最多可达100000,并且POJ经常越界测试,所以超时就再所难免了。

    再看看有没有其他的算法呢,上面我们是从1→i和i+1→n分别测试,1→i和i+1→n的区别就在于前者的头不动,后者的尾巴不动,如果我们把后者倒过来算,这样两者就一样了,时间会不会缩减呢。这里我们干脆把整个数组按照DP2专题中的方法正着来一遍,反着来一遍,然后取left[i]+right[i+1]即可。

    代码如下:

    

/*Memory: 1560 KB   Time: 204 MS  
Language: GCC   Result: Accepted  
 
This source is shared by hust_lcl
*/
#include <stdio.h>
#define SIZE 100010
int input[SIZE];
int left[SIZE];
int right[SIZE];
int main()
{
    int n , i , j , max , flag , t;
    while(scanf("%d",&n),n)
    {
        for(i = 1 ; i <= n ; i++)
          scanf("%d",&input[i]);
        left[1] = input[1];
        for(i = 2 ; i <= n ; i ++)
        {
            if(left[i-1]>0)
              left[i] = input[i] + left[i-1];
            else
              left[i] = input[i];
        }
        right[n] = input[n];
        t = 0;
        for(i = n-1 ; i >=1 ; i --)
        {
            if(right[i+1]>0)
            {
                if(input[i]>0)
                  right[i] = right[i+1] + input[i];
                else
                  right[i] = right[i+1];
            }
            else
            {
                if(input[i]<0)
                  right[i] = input[i]>right[i+1]?input[i]:right[i+1];
                else
                  right[i] = input[i];
            }
        }
        max = left[1] + right[2];
        for(i = 2 ; i <=n - 1 ; i ++)
        {
            if(left[i]+right[i+1] > max)
              max = left[i] + right[i+1];
        }
        printf("%d\n",max);

    }
}


   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值