n个数,从中取出m个子段,使其和最大。
dp(i,j)代表前j个元素,i个子段的最大和,第i个子段包含第j个元素。 e[j]代表第j个元素值
dp(i,j)=MAX{ dp[i][j-1] + e[j] , MAX{ dp[i-1][i~j-1] } + e[j] } 要么把第j个元素加到第i个子段里,要么把第j个元素当作 i子段的第一个元素
O(m*n*n)所以,要再优化。 dp(i,j)只与dp(i,j-1)和dp(i-1, i~j-1)有关。所以我们用now和pre两个一维数组去存储dp(i)和dp(i-1)。
我们只要保存下dp(i-1,i~j-1)的最大值就不用再去寻找了,因为在寻找第i个子段时,pre[j-1]用过一次后下次不用了,只有在寻找i+1子段时才用到,所以用过后修改pre[j-1],使其存储now[i~j-1]的最大值,以便下次寻找i+1子段时可以快速取用。
#include<stdio.h>
#include<string.h>
int now[1111111],pre[1111111];//now 存储dp(i) pre存储dp(i-1)
int n,m,e[1111111];
int Max(int a,int b){
return a>b?a:b;
}
int main(){
while(scanf("%d%d",&m,&n)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&e[i]);
}
memset(pre,0,sizeof(pre));
memset(now,0,sizeof(now));
int max;
for(int i=1;i<=m;i++){
max=0x80000000;
for(int j=i;j<=n;j++){
now[j]=Max(now[j-1],pre[j-1])+e[j];
pre[j-1]=max;
if(now[j]>max) max=now[j];
}
pre[n]=max;
}
printf("%d\n",max);
}
return 0;
}