您的位置:首页 > 其它

hdu 1024 max sum plus plus

2015-10-30 10:44 381 查看
刚写这题时知道是dp但动态转移方程推不出来,后来上网上搜了题解。

先把问题简化,假如就选一段,这就是个经典的max sum dp。

状态转移方程为dp[i]=dp[i-1]+a[i]>a[i]?:dp[i-1]+a[i]:a[i];

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1003

再说这道题http://acm.hdu.edu.cn/showproblem.php?pid=1024;

题意是求不相交且连续的多个子列和的最大值。由一段找最大然后可以想到开一个二维数组dp[i][j];每个状态可理解为分为i段时第j个元素选入时的最大值,所以要么选第j个数时在上一层的基础上从新将第j个数开为一段,要么在本层的基础上加上第j个数,又应为是要最优,自然就要最大,所以得状态转移方程dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][k])+a[j](i-1<=k<j));

由于给的范围很大<=1000000;开2维的数组爆内存,所以是否一维的可以,我一开始想时是开两个数组交替,反正只和本层和上层有关,但太麻烦,要交替赋值,时间耗费大。

没次的更新需要用到上一层的到i-1~j-1为止的最大值,所以可以开个数组记录;方程就变成dp[j]=max(dp[j-1]+a[j],pre[j]+a[j]);

最后找dp
~dp[p]的最大就行了,n为要分的段,p为元素总个数。

下面看两段代码:

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
typedef long long ll;
ll a[1000005];
ll aa[1000005];//dp数组
ll b[1000005];//记录i-1~j-1的最大值数组
//ll pp[1000005];
int main(void)
{
ll i,j,k,p,q,l,n,m;
while(scanf("%lld",&m)!=EOF)
{
scanf("%lld",&p);
if(m>p)//m不可能超过p
{
m=p;
}
for(i=1; i<=p; i++)
{
scanf("%lld",&a[i]);
}

aa[0]=0;
memset(b,0,sizeof(b));//每一次b都要初始化
for(i=1; i<=m; i++)
{
for(j=i; j<=p; j++)
{
aa[j]=aa[j-1]+a[j]>b[j]+a[j]?aa[j-1]+a[j]:b[j]+a[j];

}
b[i]=aa[i];//本层循环完后更新b数组每次更新要从第i个数开始因为要分成i+1段就必须从能分成i段时加一个数,而分i段必须要i个数。
for(j=i+1; j<=p; j++)
{
b[j]=aa[j-1]>b[j-1]?aa[j-1]:b[j-1];
}
}
ll maxx=aa[m];

for(i=m; i<=p; i++)
{
if(maxx<aa[i])
{
maxx=aa[i];
}
}

printf("%lld\n",maxx);

}

return 0;

}


#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
typedef long long ll;
ll a[1000005];
ll aa[1000005];
ll b[1000005];
//ll pp[1000005];
int main(void)
{
ll i,j,k,p,q,l,n,m;
while(scanf("%lld",&m)!=EOF)
{
scanf("%lld",&p);
if(m>p)
{
m=p;
}
for(i=1; i<=p; i++)
{
scanf("%lld",&a[i]);
}

aa[0]=0;
memset(b,0,sizeof(b));
for(i=1; i<=m; i++)
{
for(j=i; j<=p; j++)
{
aa[j]=aa[j-1]+a[j]>b[j]+a[j]?aa[j-1]+a[j]:b[j]+a[j];
if(j==i)
{
b[j]=aa[i];
}
else
{
b[j]=aa[j-1]>b[j-1]?aa[j-1]:b[j-1];//此处优化了一下b的更新直接和aa的更新合并并不要在开一重,提高了代码的效率。
//因为当前是更新aa[j]所以b[j]记录的是i-1到j-1的最大更新完aa后再更新b并不影响aa[j+1]的更新b[j+1]还是上一层的更新完才变本层的。
}

}

}
ll maxx=aa[m];

for(i=m; i<=p; i++)
{
if(maxx<aa[i])
{
maxx=aa[i];
}
}

printf("%lld\n",maxx);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: