【动态规划最大子列和】HDU-1231 最大连续子序列

本文详细解析了最大子列和问题的动态规划解法,通过设置dp[]数组记录以i结尾的最大子列和,结合start[]数组追踪起始位置元素值。文章介绍了状态转移方程,特别注意了初始化及全负数输入的处理。

在这里插入图片描述

注解

此题与hdu1003是类似的。只是输入输出的格式略有不同。
核心仍然是动态规划法求最大子列和。
下面把hdu1003的博客复制过来稍加改动:
1、用动态规划方法解决最大子列和问题。关键是设置一个dp[]数组,dp[i]表示以i结尾的最大子列和。
如dp[0]表示以0作为结尾的最大子列和,dp[1]表示以1作为结尾的最大子列和。
因此,要求出整个序列的最大子列和,只需要从头到尾遍历dp,找出最大值。这是最原始的最大子列和问题的解法。
2、本题除了要求输出最大和,还要求输出起始位置元素值和终止位置元素值。这就要在dp[]数组的基础上,再增加start[]数组,start[i]表示以i作为结束的最大和的起始位置元素值。
3、动态规划的核心:找出状态转移方程:dp[i] = max(a[i], dp[i-1]+a[i])。
本质就是,如果dp[i-1]>=0,dp[i]就等于dp[i-1]+a[i]。如果dp[i-1]<0,就输出a[i]。
4、一个小的注意点:初始化。题目不保证所有数字都是非负数,因此初始化答案时,应该是用第一个数字初始化。而不能简单用一个负数。因为可能出现所有数字都比这个负数小的情况,这样这个负数就会被误当成最终答案而输出。
5、此题额外增加了一种情况,当输入全部为负数时,要输出0,所以代码中需要增加一个是否全为负数的判断。技巧是用flag。

代码

#include <iostream>
#include <string.h>

using namespace std;

const int MAX = 10001;
int a[MAX];
int dp[MAX];
int start[MAX];

void process(int len) {
	dp[0] = a[0];
	start[0] = 0;
	for(int i=1; i<len; i++) {
		if(a[i]>dp[i-1]+a[i]) {
			dp[i] = a[i];
			start[i] = a[i];
		} else {
			dp[i] = dp[i-1]+a[i];
			start[i] = start[i-1];
		}
	}
}

int main() {
	int n;
	scanf("%d", &n);
	while(n) {
		memset(a, 0, sizeof(a));
		memset(dp, 0, sizeof(dp));
		memset(start, 0, sizeof(start));
		int isallNegative = 1;
		for(int j=0; j<n; j++) {
			scanf("%d", &a[j]);
			if(a[j]>=0) {
				isallNegative = 0;
			}
		}
		if(isallNegative) {
			printf("%d %d %d\n", 0, a[0], a[n-1]);
		} else {
			process(n);
			int max = dp[0];
			int ansStart = a[0];
			int ansEnd = a[0];
			for(int j=1; j<n; j++) {
				if(dp[j]>max) {
					max = dp[j];
					ansStart = start[j];
					ansEnd = a[j];
				}
			}
			printf("%d %d %d\n", max, ansStart, ansEnd);
		}

		scanf("%d", &n);
	}

	return 0;
}

结果

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值