hdu1024(基本dp)

/*
translation:
	给出一串数列,求m个不相交的段最大的和是多少?
solution:
	基本dp。
	设dp[i][j]表示前j个数划分成i段,所得到的最优解。
	对于第j个数,有两种决策,一种是单独成立成一个段。另一种是和地i个段组成一段。
	所以有转移方程如下:dp[i][j]=max{dp[i][j-1], max{dp[i-1][k]}} + a[i]。其中k>=1 && k <= j-1
	由于数据量太大,所以不能开二维数组。必须利用滚动数组。
	再进一步观察可以发现,max{dp[i-1][k]}可以通过每次循环的更新来求出。如此以来,复杂度从O(mn^2)降成O(mn)
note:
	1:注意最后输出时要输出tmp,原因见注释
	# 状态的表示方法想错了,一开始想法是求出数列中和最大的段,在依次求出次小的。。。正确与否未知,但明显超时
	* 关于状态表示方法的设计有个小诀窍,可以将题中所有的有关参数都列出来,将其依次组合。再推其转移方程,如果转移方程
	  满足动态规划的一系列要求,既是正确方法
	* 若是有遇到数据量过大开不下多维数组的情况,可以考虑在开一个一维数组来代替。
date:
	2016.10.29
*/
#include 
#include 
#include 

using namespace std;
const int maxn = 1000000 + 5;
const int inf = 1e8;
typedef long long ll;

int dp[maxn], a[maxn], pre[maxn];
int n, m;

int main()
{
	//freopen("in.txt", "r", stdin);
    while(~scanf("%d%d", &m, &n)){
		memset(dp, 0, sizeof(dp));
		memset(a, 0, sizeof(a));
		memset(pre, 0, sizeof(pre));

		for(int i = 1; i <= n; i++)	scanf("%d", &a[i]);

		int tmp;
		for(int i = 1; i <= m; i++){
			tmp = -inf;
			for(int j = i; j <= n; j++){
				dp[j] = max(dp[j-1], pre[j]) + a[j];
				pre[j] = tmp;
				tmp = max(tmp, dp[j]);
			}
		}
		printf("%d\n", tmp);	//答案就是最后一轮的最大值
								//不能输出dp[n],因为最后一轮的最大值不一定以n结尾
    }
    return 0;
}

你可能感兴趣的:(=====动态规划=====,基本dp)