NEUQ OJ 1486【动态规划★★】Max Sum Plus Plus.【一维数组,记忆优化】

【动态规划★★】Max Sum Plus Plus.

题目描述
给你一个长度为n的数组(1<=n<=1000000),数组中n个元素S 1, S 2, S 3, S 4 … S n(-32768 ≤ S x ≤ 32767)
我们定义函数sum(i,j) = S i + … + S j (1 ≤ i ≤ j ≤ n)
现在给你一个整数m(0<m<=n)你需要求出 y=sum(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + … + sum(i m, j m) 的最大值,(i x ≤ i y ≤ j x or i x ≤ j y ≤ j x 是不被允许的)

输入描述
有多组数据,对于每一组数据,只占一行,输入两个数m和n,然后后面输入n个数S 1, S 2, S 3 … S n

输出描述
对于每组数据,每组输出占一行,每组输出一个数表示y的最大值
样例输入
1 3 1 2 3
2 6 -1 4 -2 3 -2 3
样例输出
6
8

解题思路

最大和子序列问题吧
大致意思就是,给你一串数,取出m段,使得这m段的和最大

不看题目的话,刚开始没有很清晰的思绪。看了也没有。。。

嗯,,

  1. 就是把情况映射到一个二维数组中。第一列是数组中的数,第一行是取得段得情况

  2. 模拟这个矩阵得计算过程就能的到最后的结果了。模拟过程中最重要的就是转移方程了,即决策过程
    决策分为两种
    - 第 j 个数加在第j-1数得段后面
    - 第 j 个数为新段 段首
    决策方程:

    d[n] = max(d[n] , max( d[j-1] , temp ) + a[j] );

    把它分开写

    temp = max(d[j-1],temp) + a[j];
    d[n] = max(d[n],temp);

  3. 解题

    1. 接收数,初始化dp数组

      for(int i=1;i<=n;i++)
      cin>>a[i];
      memset(dp,0,sizeof (dp) );

    2. 模拟计算,遍历字段

      for(int i=1;i<=m;i++)

    3. 求前i项得和(这个时候每一项是一段)获得决策2

      int temp=0;
      for(int k =1;k<=i;k++)
      temp += a[k];
      ans = temp;

    4. for(int j = i+1 ;j<=n;j++)

    5. 将 dp[ j-1 ] 和加上 a[ j ] 相比较 获得决策1(考虑负数)

      temp = max(dp[j-1],temp) + a[j];

    6. 更新d[ j-1 ],(优化,记忆)

      dp[j-1] = ans;

    7. 更新ans,比较决策,max( 决策1,决策2)

      ans = max(temp,ans);

还有一些细节,数组的初始化,内存的分配等。完整代码中可以看出来。

代码

#include<iostream>
#include<string.h>
#define max(a,b) (a>b?a:b)
using namespace std;
int m,ans;
long long n;
int a[1000005];
int dp[1000005];
int main()
{
	while((scanf("%d %d",&m,&n) )!=EOF) //cin>>m>>n;
	{
		for(int i=1;i<=n;i++)
			cin>>a[i];
		memset(dp,0,sizeof (dp) );
		for(int i=1;i<=m;i++)
		{
			int temp=0;//***
			for(int k =1;k<=i;k++)
			{
				temp += a[k];
			}
			ans = temp;
			for(int j = i+1 ;j<=n;j++)
			{
				temp = max(dp[j-1],temp) + a[j];
				dp[j-1] = ans;
				ans = max(ans,temp);
			}
		}
		cout<<ans<<endl;
	}
	return 0;
	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值