【动态规划★★】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段的和最大
不看题目的话,刚开始没有很清晰的思绪。看了也没有。。。
嗯,,
-
就是把情况映射到一个二维数组中。第一列是数组中的数,第一行是取得段得情况
-
模拟这个矩阵得计算过程就能的到最后的结果了。模拟过程中最重要的就是转移方程了,即决策过程
决策分为两种
- 第 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); -
解题
- 接收数,初始化dp数组
for(int i=1;i<=n;i++)
cin>>a[i];
memset(dp,0,sizeof (dp) ); - 模拟计算,遍历字段
for(int i=1;i<=m;i++)
- 求前i项得和(这个时候每一项是一段)获得决策2
int temp=0;
for(int k =1;k<=i;k++)
temp += a[k];
ans = temp; -
for(int j = i+1 ;j<=n;j++)
- 将 dp[ j-1 ] 和加上 a[ j ] 相比较 获得决策1(考虑负数)
temp = max(dp[j-1],temp) + a[j];
- 更新d[ j-1 ],(优化,记忆)
dp[j-1] = ans;
- 更新ans,比较决策,max( 决策1,决策2)
ans = max(temp,ans);
- 接收数,初始化dp数组
还有一些细节,数组的初始化,内存的分配等。完整代码中可以看出来。
代码
#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;
}