暑期dp46道(18)--HDOJ 1024 Max Sum Plus Plus

题目链接:HODJ 1024


这题花的时间蛮多的,不过没有浪交,就是之前有几位做过的说这题很“巧”,需要费时间,我才没敢轻易交,大概花了一天时间交了一发,A掉,还多开了内存,尴尬,不过确实挺巧的,dp降低复杂度的妙用或许就在这吧;


题意:相信大家都能看懂,就是给定一个序列a1,a2.....an;求把它分为m个单独序列的最大值;



题解:这题状态方程其实是不难想的,但是可能会被顾忌到复杂度,刚开始就想着直接有效的算法,结果怎么都找不到,dp还是应该先找解法,再优化的。

对于一个长为i的序列,分成j个单独序列的最优解:

a[i]在这j个序列内 

dp[i][j]=max(dp[i-1][j]+a[i],dp[k][j-1]+a[i])(k>=0&&k<i)

然后对于dp[k][j-1]这段最大值 只要记录下就好了


代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>//sort(); 
#include<climits>
using namespace std;
#define debug 0
#define M(a) memset(a,0,sizeof(a))
#define Max(a,b) ((a>b)?a:b)

const int maxn = 1000000+5;
int data[maxn],dp[maxn],temp[maxn];
int n,m;

void Do()
{
	int ans;
	for(int i = 1;i <= n;i++)
	{
		ans = INT_MIN;
		for(int j = i;j <= m;j++)//这里dp[j]表示当前长为j的序列分为i段的最优解
		{
			dp[j] = Max(dp[j-1] + data[j],temp[j-1] + data[j]);//temp[j-1]保存的是长为1->j-1的序列分为
			temp[j-1] = ans;                                   //i-1段的最优解
			ans = Max(ans,dp[j]);//ans保存长为i->j的序列分为i段最优解Max,即为最终最优解
		}
	}
	printf("%d\n",ans);
} 
int main()
{
#if debug
	freopen("in.txt","r",stdin);
#endif//debug
	while(~scanf("%d%d",&n,&m))
	{
		M(dp);
		M(temp);
		for(int i = 1;i <= m;i++)
		{
			scanf("%d",&data[i]);
		}
		Do(); 
	}
	return 0;
}
 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值