poj2479-在一个数组中求任意不相交的两个子数组之和的最大值

该题的重点在于求一个数组中子数组之和的最大值,采用动态规划的方法求解,已知数组A[n]

  1. 假设已求得了A[i,n]中子数组之和的最大值,那么将A[i-1]加入进来后就出现了3种情况。
  2. A[i-1]就是A[i-1,n]中子数组之和的最大值
  3. A[i-1,...,j](i<=j<=n)就是A[i-1,n]中和最大的子数组
  4. A[i-1]加进来后对子数组之和的最大值没有影响
  5. 令A[i,n]子数组之和的最大值为nAll,以A[i]开头的,且是A[i,n]的子数组,其和的最大值为nStart
  6. 则A[i-1,...,j]子数组之和的最大值为max(nAll, max(A[i],A[i] + nStart))
  7. 按上述公式,对数组循环一次就可以求得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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值