该题的重点在于求一个数组中子数组之和的最大值,采用动态规划的方法求解,已知数组A[n]
- 假设已求得了A[i,n]中子数组之和的最大值,那么将A[i-1]加入进来后就出现了3种情况。
- A[i-1]就是A[i-1,n]中子数组之和的最大值
- A[i-1,...,j](i<=j<=n)就是A[i-1,n]中和最大的子数组
- A[i-1]加进来后对子数组之和的最大值没有影响
- 令A[i,n]子数组之和的最大值为nAll,以A[i]开头的,且是A[i,n]的子数组,其和的最大值为nStart
- 则A[i-1,...,j]子数组之和的最大值为max(nAll, max(A[i],A[i] + nStart))
- 按上述公式,对数组循环一次就可以求得A[i,n](1<=i<=n)子数组之后的最大值
题意是要求两个不相交的子数组之后的最大值,那么只需要按从高到低和从低到高的次序对数组遍历一次,求得A[i,n](1<=i<=n)和A[1,j](1<=i<=n)子数组之和的最大值,然后再将其两两相加,所得的最大值就是要求的结果
#include <stdio.h>
/*从低位往高位计算*/
void MaxSum(int *A, int *nAll, int start, int end)
{
int nStart;
int i;
nStart = A[start];
nAll[start] = A[start];
for (i = start + 1; i <= end; ++i)
{
/*比较A[i]与 A[i]+nStart*/
if (nStart < 0)
nStart = 0;
nStart += A[i];
/*比较max(A[i],A[i]+nStart)与nAll*/
if (nStart > nAll[i - 1])
nAll[i] = nStart;
else
nAll[i] = nAll[i - 1];
}
}
/*从高位往低位计算*/
int MaxSumReverse(int *A, int *nAll, int start, int end)
{
int nStart, nMax;
int i;
int maxSum = -50000, sum;
MaxSum(A, nAll, start, end - 1);
nStart = A[end];
nMax = A[end];
sum = nMax + nAll[end - 1];
if (sum > maxSum)
maxSum = sum;
for (i = end - 1; i > start; --i)
{
/*比较A[i]与 A[i]+nStart*/
if (nStart < 0)
nStart = 0;
nStart += A[i];
/*比较max(A[i],A[i]+nStart)与nAll*/
if (nStart > nMax)
nMax = nStart;
sum = nMax + nAll[i - 1];
if (sum > maxSum)
maxSum = sum;
}
return maxSum;
}
int main()
{
int T;
int N;
int A[50010], nAll[50010];
int i, j;
scanf("%d", &T);
while (T--)
{
scanf("%d", &N);
for (i = 0; i < N; ++i)
{
scanf("%d", &A[i]);
}
printf("%d\n", MaxSumReverse(A, nAll, 0, N - 1));
}
return 0;
}