传送门: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.
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
POJ Monthly--2005.08.28,Li Haoyuan
题目大意: 取数组中分开的连续两段,使其总和最大。
分析:这题和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);
}
}