首页 > 代码库 > HDU 1024 Max Sum Plus Plus Dp题解

HDU 1024 Max Sum Plus Plus Dp题解

本题就是求m段子段,而且要求这些子段加起来和最大,最大子段和的Plus版本。

不过题意真的不好理解,x,y什么的都没有说清楚。

知道题意就开始解题了,这肯定是动态规划法了。

动态规划法的程序不难写,关键是抽象思维。

这里的最小情况是只分成一段的时候,就退化为最大子段和问题了,这个是段数的最小情况了; 如果只有0个数的时候,结果肯定为零了,或者如果只有一个数的时候就是这个数了,那么数列只有0个或者1个的时候就是数组的最小情况了。

然后记录使用一个数组记录dp[MAX_N],其中dp[i]的含义就是在一定选择i这个数的时候得到的最大和值。

这样如果分成i段,有j个数的时候dp[j] = max(dp[j-1]+arr[j], MAX[j-1]+arr[j]),其实如果使用二维数组,那么MAX[j-1] == dp[[i-1][j-1]这个状态格的数值,表示分成i-1段的时候,有j-1个数的值。取max就是表示arr[j]是直接和dp[j-1]即接在后面第i段,还是独立成为一段的值比较大,选择最优方案,取最大值。这里的记录数据方案就是所谓的滚动数组了。不过我分开两个数组罢了。

抽象思维,比较难理解的,代码还是很好写的。

#include <stdio.h>
#include <vector>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <limits.h>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;

const int MAX_N = 1000001;
int dp[MAX_N], MAX[MAX_N], arr[MAX_N];

int main()
{
	int n, m, maxSum;
	while (~scanf("%d %d", &m, &n))
	{
		memset(MAX, 0, sizeof(int) * (n+1));
		memset(dp, 0, sizeof(int) * (n+1));
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", arr+i);
		}
		for (int i = 1; i <= m; i++)
		{
			maxSum = INT_MIN;
			for (int j = i; j <= n; j++)
			{
				dp[j] = max(dp[j-1]+arr[j], MAX[j-1]+arr[j]);
				MAX[j-1] = maxSum;	//not overflow here
				maxSum = max(maxSum, dp[j]);
			}
		}
		printf("%d\n", maxSum);
	}
	return 0;
}