【原】 POJ 2479 Maximum sum 动态规划 解题报告
http://poj.org/problem?id=2479
方法:两次dp+一次扫描,复杂度3*n
基于求最大连续子数组的线性dp算法
对数组从前往后各做一次O(n)的dp,求得maxsofar[0][0...n-1],再数组从后往前各做一次O(n)的dp,求得maxsofar[1][0...n-1],
再扫描一遍maxsofar求得maxsofar[0][i-1] + maxsofar[1][i]的最大值,即为结果
线性dp:将大问题转化为小问题来处理
对于数组a[0...n-1],a[n-1]和最终结果max subarray a[i...j]之间的关系可能有三种情况:
(1) i=j=n-1,则max subarray为a[n-1]
(2) i<j=n-1,则max subarray为a[i...n-1]
(3) i<j<n-1,则max subarray为a[i...j]
设maxendinghere[i]表示a[0..i]中包含a[i]的子数组的最大和,maxsofar[i]表示a[0...i]中最大子数组的和
因此可以看出大问题可转化为小问题来解决:a[0...i]的最大子数组的和是以下三者的最大值:
a[i],a[0...i-1]中包含a[i-1]的最大子数组的和加a[i],a[0...i-1]的最大子数组的和
递归式为:maxsofar[i] = max( a[i] , maxendinghere[i-1]+a[i] , maxsofar[i-1] )
Description
Given a set of n integers: A={a1, a2,..., an}, we define a function d(A) as below:
Your task is to calculate d(A).
Input
The input consists of T(<=30) test cases. The number of test cases (T) is given in the first line of the input.
Each test case contains two lines. The first line is an integer n(2<=n<=50000). The second line contains n integers: a1, a2, ..., an. (|ai| <= 10000).There is an empty line after each case.
Output
Print exactly one line for each test case. The line should contain the integer d(A).
Sample Input
1
10
1 -1 2 2 3 -3 4 -4 5 -5
Sample Output
13
Hint
In the sample, we choose {2,2,3,-3,4} and {5}, then we can get the answer.
Huge input,scanf is recommended.
1: const int N = 50000 ;
2:
3: int a[N] ;
4: int maxsofar[2][N] ;
5:
6: void run2479()
7: {
8: int t,n,val ;
9: int i,j ;
10: int maxendinghere ;
11: int max ;
12: int sum ;
13:
14: scanf( "%d", &t ) ;
15: while( t-- && scanf( "%d", &n ) )
16: {
17: scanf( "%d", &a[0] ) ;
18: maxendinghere = a[0] ;
19: maxsofar[0][0] = a[0] ;
20: for( i=1 ; i<n ; ++i ) //输入数组的同时做从前往后的dp
21: {
22: scanf( "%d", &a[i] ) ;
23: maxendinghere = std::max( a[i] , maxendinghere+a[i] ) ;
24: maxsofar[0][i] = std::max( maxsofar[0][i-1] , maxendinghere ) ;
25: }
26:
27: maxendinghere = a[n-1] ;
28: maxsofar[1][n-1] = a[n-1] ;
29: max = maxsofar[0][n-2] + a[n-1] ;
30: for( i=n-2 ; i>0 ; --i ) //做从后往前的dp同时求得最大值
31: {
32: maxendinghere = std::max( a[i] , a[i]+maxendinghere ) ;
33: maxsofar[1][i] = std::max( maxsofar[1][i+1] , maxendinghere ) ;
34: sum = maxsofar[0][i-1] + maxsofar[1][i] ;
35: max = max>sum ? max : sum ;
36: }
37: printf( "%d\n" , max ) ;
38: }
39: }