HDOJ 1024 Max Sum Plus Plus
题目
分类
动态规划
题意
给出 n 个数的序列
取 m 对 (i , j)
求 sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + … + sum(im, jm)的最大值
题解
m对序列的最大和
联想序列最大和
设 dp[i][j] 是 以j结尾的前j个元素分成i段的最大值
则 以j结尾的前j个元素分成i段的最大值 是 以j-1结尾的前j-1个元素分成i段的最大值 + j 和 以 k 结尾的前k个元素分成i-1段的最大值 + j 的 最大值 (i-1 <= k < j)
此题思路非原创 参考 firstlove的博客 hdu 1024 最大M子段和
这篇写的非常好 即推出了动态转移方程,又分析了上下界给出了递推例子,还做了优化,强烈推荐一看
技巧
本题递推之和当前行和前一行有关
可以只申请两行空间
每次交换下标 即可 节省很多空间
例如
t = 1(t在第1行)
执行 t = 1 - t ( t = 0 )
在执行 t = 1 - t ( t = 1)
由此可在 0,1 行直接切换
代码
#include <iostream>
#define nummax 1000001
#define ninf -311111111
using namespace std;
int dp[2][nummax];
int a[nummax];
int max(int & a,int & b);
int main()
{
int m,n,t,pmax,res;
while(cin >> m >> n)
{
t = 1;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
dp[0][i] = 0;
}
for(int i = 1;i <= m;i++)
{
dp[t][i] = dp[1-t][i-1] + a[i];
pmax = dp[1-t][i-1];
for(int j = i + 1;j <= n - m + i;j++)
{
pmax = max(pmax,dp[1-t][j-1]);
dp[t][j] = max(dp[t][j-1],pmax) + a[j];
}
t = 1-t;
}
t = 1-t;
res = ninf;
for(int i = m;i <= n;i++)
if(res < dp[t][i])
res = dp[t][i];
cout << res << endl;
}
return 0;
}
int max(int & a,int & b)
{
if(a >= b)
return a;
else return b;
}