POJ 2479 Maximum sum

题目大意:

        现有多个测例(测例数题中给出),对于每个测例都会给定一序列,长度为N(2 ≤ N ≤ 5,000),序列中每个元素的范围为[-10000, 10000],对于每个测例都输出序列中两个不相交子段的和的最大值,子段必须是连续的。

题目链接

注释代码:

/*                                         
 * Problem ID : POJ 2479 Maximum sum
 * Author     : Lirx.t.Una                                         
 * Language   : C++                        
 * Run Time   : 422 ms                                         
 * Run Memory : 720 KB                                         
*/ 

#include <stdio.h>

//表示数组中元素的无穷小值
#define	RINF		-10001

//序列的最大长度
#define	MAXN		50001

#define	MAX(x,y)	( (x) > (y) ? (x) : (y) )

int		a[MAXN];//array,表示序列,下标从1开始
//lft[i]和rht[i]在初始化时表示以i为右边界和左边界的子序列的最大和
//在动态规划时将会被跟新为
//以i为右边界和左边界的子序列的最大和
int		lft[MAXN], rht[MAXN];

int
main() {

	int		t;//测例数
	int		n;//元素个数
	int		i;//技术变量
	int		tmp;//临时变量
	
	int		ans;

	scanf("%d", &t);
	while ( t-- ) {
	
		scanf("%d", &n);
		for ( i = 1; i <= n; i++ )
			scanf("%d", a + i);

		//序列最大不相交子段和等于左序列最大子段和右序列最大子段之和

		//对左序列初始化
		lft[1] = a[1];
		for ( i = 2; i <= n; i++ )
			if ( lft[i - 1] <= 0 )//若以i - 1号元素为右边界的子序列和小于0
				lft[i] = a[i];//则直接将lft[i]初始化为a[i]即可,此时该序列只有i一个元素
			else
				lft[i] = lft[i - 1] + a[i];//否则在之前序列基础上加上该元素

		//由于任何子段都肯定有一个末尾(边界)元素,因此根据这点
		//将lft[i]更新为最大子段和
		for ( i = 2; i <= n; i++ )//此时lft[i - 1]已经被更新成以i - 1有右边界的左序列
			//的最大和,而lft[i]还是之前的以i为右边界的子序列的和
			lft[i] = MAX( lft[i - 1], lft[i] );

		//有序列同理
		rht[n] = a[n];
		for ( i = n - 1; i >= 1; i-- )
			if ( rht[i + 1] <= 0 )
				rht[i] = a[i];
			else
				rht[i] = rht[i + 1] + a[i];

		for ( i = n - 1; i >= 1; i-- )
			rht[i] = MAX( rht[i + 1], rht[i] );

		for ( ans = RINF, i = 1; i < n; i++ ) {//根据断点的不同
			//找出具有最大不相交子段和的分法
			
			tmp = lft[i] + rht[i + 1];
			ans = MAX( ans, tmp );
		}
		
		printf("%d\n", ans);
	}
	
	return 0;
}

无注释代码:

#include <stdio.h>

#define	RINF		-10001

#define	MAXN		50001

#define	MAX(x,y)	( (x) > (y) ? (x) : (y) )

int		a[MAXN];
int		lft[MAXN], rht[MAXN];

int
main() {

	int		t;
	int		n;
	int		i;
	int		tmp;
	
	int		ans;

	scanf("%d", &t);
	while ( t-- ) {
	
		scanf("%d", &n);
		for ( i = 1; i <= n; i++ )
			scanf("%d", a + i);

		lft[1] = a[1];
		for ( i = 2; i <= n; i++ )
			if ( lft[i - 1] <= 0 )
				lft[i] = a[i];
			else
				lft[i] = lft[i - 1] + a[i];
		for ( i = 2; i <= n; i++ )
			lft[i] = MAX( lft[i - 1], lft[i] );

		rht[n] = a[n];
		for ( i = n - 1; i >= 1; i-- )
			if ( rht[i + 1] <= 0 )
				rht[i] = a[i];
			else
				rht[i] = rht[i + 1] + a[i];
		for ( i = n - 1; i >= 1; i-- )
			rht[i] = MAX( rht[i + 1], rht[i] );

		for ( ans = RINF, i = 1; i < n; i++ ) {

			tmp = lft[i] + rht[i + 1];
			ans = MAX( ans, tmp );
		}

		printf("%d\n", ans);
	}

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值