week12作业C hdu-1024

在这里插入图片描述
用dp[i][j]代表前j个数中,以a[j]结尾,分成i组的最大和。
状态转移方程:dp[i][j]=max(max(dp[i-1][k])+a[j],dp[i][j-1]+a[j]) 其中(i-1<=k<=j-1)。
情况1:max(dp[i-1][k])+a[j]表示第j个数a[j]独自作为一组,前k个数中找出以a[k]为结尾,分成i-1组。这样正好有i组,同时,因为i-1组至少有i-1个数,至多有j-1个数,所以i-1≤k≤j-1。
情况2:dp[i][j-1]+a[j]表示第j个数加入以a[j-1]结尾的第i组。
但是,这样空间复杂度和时间复杂度都太大了。
通过观察,我们发现dp[i][j]仅仅使用到了dp[i-1]中的i-1到j-1的最大值,即 max(dp[i-1][k]),i-1≤k≤j-1。所以,我们可以用数组premax为记录dp[i][j]记录dp[i-1][k]中相应范围的最大值,这样就可以少一层循环,同时二维数组dp[i][j]变成了dp[j],dp[j]表示从以a[j]结尾的最大和。
所以,转换方程变成了dp[j]=max(premax[j-1],dp[j-1])+a[j]。premax[j-1]相当于情况1,max(dp[i-1][k]),i-1≤k≤j-1,a[j]独自一组,而dp[j-1]表示情况2,a[j]加入以a[j-1]为结尾的组。

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int M,N;
int a[2000000],dp[2000000],premax[200000];
int main()
{
	while(scanf("%d%d",&M,&N)!=EOF)
	{
		for(int i=1;i<=N;i++)
		{
			scanf("%d",&a[i]);
		}
		memset(dp,0,sizeof(dp));
		memset(premax,0,sizeof(premax));
		int temp;
		for(int i=1;i<=M;i++)
		{
			temp=-1e9;
			for(int j=i;j<=N;j++)
			{
//				cout<<"d[j]=max(premax[j-1]("<<premax[j-1]<<"),dp[j-1]("<<dp[j-1]<<")])+a[j]=("<<a[j]<<")"<<'\n'; 
				dp[j]=max(premax[j-1],dp[j-1])+a[j];
//				cout<<"temp="<<temp<<'\n';
				premax[j-1]=temp;//temp存放i~j-1中的最大值
//				cout<<"temp=max(temp("<<temp<<"),dp[j]=("<<dp[j]<<")"<<'\n';
				temp=max(temp,dp[j]);
			}
		}
		printf("%d\n",temp);
	}
}

动态规划感觉一直掌握的不好,自己写题目经常想不出状态的表示和状态转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值