【原】 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: }
posted @ 2010-11-05 19:45  Allen Sun  阅读(751)  评论(0编辑  收藏  举报