具有约束的数组中的最大总和

时间:2012-04-21 18:01:46

标签: algorithm

我有这个问题,给定一个正数组,我必须找到元素的最大总和,这样就不会选择两个相邻的元素。最大值必须小于某个给定的K.我试着考虑没有k的类似问题的界限,但到目前为止我都失败了。我对后一个问题有以下dp-ish soln

    int sum1,sum2 = 0;
    int sum = sum1 = a[0];

    for(int i=1; i<n; i++)
    {
        sum = max(sum2 + a[i], sum1);
        sum2 = sum1;
        sum1 = sum;
    }

有人可以给我一些关于如何处理我目前问题的提示吗?

4 个答案:

答案 0 :(得分:4)

我能想到的最好的是O(n * K)dp:

int sums[n][K+1] = {{0}};
int i, j;
for(j = a[0]; j <= K; ++j) {
    sums[0][j] = a[0];
}
if (a[1] > a[0]) {
    for(j = a[0]; j < a[1]; ++j) {
        sums[1][j] = a[0];
    }
    for(j = a[1]; j <= K; ++j) {
        sums[1][j] = a[1];
    }
} else {
    for(j = a[1]; j < a[0]; ++j) {
        sums[1][j] = a[1];
    }
    for(j = a[0]; j <= K; ++j) {
        sums[1][j] = a[0];
    }
}
for(i = 2; i < n; ++i) {
    for(j = 0; j <= K && j < a[i]; ++j) {
        sums[i][j] = max(sums[i-1][j],sums[i-2][j]);
    }
    for(j = a[i]; j <= K; ++j) {
        sums[i][j] = max(sums[i-1][j],a[i] + sums[i-2][j-a[i]]);
    }
}

sums[i][j]包含a[0..i]不超过j的非相邻元素的最大总和。最后解决方案是sums[n-1][K]

答案 1 :(得分:0)

  1. 制作原始数组(A1)的副本(A2)。
  2. 查找数组中的最大值(A2)。
  3. 在它的前一个邻居之前提取所有值,并将它的下一个邻居之后的值提取到一个新数组(A3)。
  4. 在新数组中找到最大值(A3)。
  5. 检查总和是否大于k。如果总和通过检查,你就完成了。
  6. 如果不是,则需要返回复制的数组(A2),删除第二个大值(在步骤3中找到)并从步骤3开始。
  7. 一旦没有可以与最大数字一起使用的数字组合(即步骤1中找到的数字+数组中的任何其他数字大于k),您将其从原始数组(A1)中删除并重新开始第0步。
  8. 如果由于某种原因没有有效的组合(例如,数组只有三个数字或没有数字的组合低于k),那么抛出异常或者如果看起来更合适则返回null。

答案 2 :(得分:0)

第一个想法:蛮力

迭代所有合法的索引组合并动态构建总和。

当你克服K时停止一个序列。

保持序列,直到找到一个更大的序列,它仍然小于K

第二个想法:也许人们可以强制分裂并征服它......

答案 3 :(得分:0)

以下是没有“k”约束的问题的解决方案,您将其作为第一步执行:https://stackoverflow.com/a/13022021/1110808

在我看来,上述解决方案可以通过简单地修改以下for循环中的if条件来容易地扩展为具有k约束,以包括约束:possibleMax&lt; ķ

// Subproblem solutions, DP
for (int i = start; i <= end; i++) {
    int possibleMaxSub1 = maxSum(a, i + 2, end);
    int possibleMaxSub2 = maxSum(a, start, i - 2);

    int possibleMax = possibleMaxSub1 + possibleMaxSub2 + a[i];
    /*
    if (possibleMax > maxSum) {
        maxSum = possibleMax;
    }
    */
    if (possibleMax > maxSum && possibleMax < k) {
        maxSum = possibleMax;
    }
}

如原始链接中所述,可以通过添加记忆来改进此方法,以便不重新计算重复子问题的解决方案。或者可以通过使用自下而上的动态编程方法来改进(当前方法是递归自顶向下方法)

您可以在此处参考自下而上的方法:https://stackoverflow.com/a/4487594/1110808