我试图解决以下问题:
我之前做过的最接近的问题是 Kadane 的算法,所以我尝试了“此处最大结尾”的方法,这导致了以下基于 DP 的程序。这个想法是将问题分解为更小的相同问题(通常的 DP)。
#include<stdio.h>
#include<stdlib.h>
main(){
int i, n, m, C[20002], max, y, x, best, l, j;
int a[20002], b[20002];
scanf("%d %d", &n, &m);
for(i=0;i<n;i++){
scanf("%d",&C[i]);
}
a[0] = C[0];
max = C[0];
for(i=1;i<n;i++){
max = (C[i]>max) ? C[i] : max;
a[i] = max;
}
for(l=0;l<n;l++){
b[l] = 0;
}
for(y=2;y<m+1;y++){
for(x=y-1;x<n;x++){
best = max = 0;
for(j=0;j<y;j++){
max += (j+1) * C[j];
}
for(i=y-1;i<x+1;i++){
best = a[i-1] + y * C[i];
max = (best>max) ? best : max;
}
b[x] = max;
}
for(l=0;l<n;l++){
a[l] = b[l];
}
}
printf("%d\n",b[n-1]);
system("PAUSE");
return 0;
}
但是这个程序在指定的时间限制内不起作用(空间限制很好)。请给我一个关于在这个问题上使用的算法的提示。
编辑。
这是代码的解释:就像在 Kadane 中一样,我的想法是查看特定的 C[i],然后对以 C[i] 结尾的 m 子序列取最大加权和,最后取所有的最大值对所有 i 的这些值。这将为我们提供答案。现在请注意,当您查看以 C[i] 结尾的 m 子序列并取最大加权和时,这相当于取 C[0] 中包含的 (m-1)-子序列的最大加权和到 C[i-1]。这是一个较小的问题,与我们原来的问题相同。所以我们使用递归。为了避免重复调用函数,我们制作了一个值表 f[i][j],其中 f[ii][j] 是问题的答案,与我们的问题相同,将 n 替换为 i,将 m 替换为j. 也就是我们建立一个f[i][j]的表,我们最终的答案是f[n-1][m](也就是我们使用memoization)。现在注意到计算条目 f[i][j] 只需要前一列,只保留数组就足够了。这些数组是“a”和“b”。
抱歉,篇幅太长,忍不住了。:(