使用动态编程来查找总和最接近给定数字M的数字子集

时间:2015-11-15 06:47:12

标签: dynamic-programming knapsack-problem subset-sum

给定一组n个正整数a1,a2,... a3和另一个正整数M,我将找到A的数字的子集,其总和最接近于M.换句话说,我' m试图找到A的子集A',使得绝对值| M - Σa∈A'|最小化,其中[Σa∈A'a]是A'数的总和。我只需返回解决方案子集A'的元素之和,而不报告实际的子集A'。

例如,如果我们将A设为{1,4,7,12}并且M = 15.那么,解决方案子集是A'= {4,12},因此算法只需要返回4 + 12 = 16作为答案。

应该运行问题的动态编程算法 最坏情况下的O(nK)时间,其中K是所有A的总和。

2 个答案:

答案 0 :(得分:1)

构建一个大小为n * K的动态编程表,其中

D[i][j] = Can you get sum j using the first i elements ?

您可以使用的递归关系是:D[i][j] = D[i-1][j-a[i]] OR D[i-1][j]如果您认为可以添加或保留第i个元素,则可以派生此关系。

时间复杂度:O(nK)其中K =所有元素的总和

最后,你迭代你可以获得的整个可能的总和,即j = 1..K的D [n] [j]。哪个最接近M将是你的答案。

答案 1 :(得分:1)

对于动态算法,我们

  1. 定义我们将使用的值
  2. 这里的值集实际上是一个表。

    对于这个问题,我们将值DP [i,j]定义为我们是否可以使用前i个元素获得和j的指标。 (1表示是,0表示否)

    这里0< = i< = n,0< = j< = K,其中K是A中所有元素的总和

    1. 定义递归关系
    2. DP [i + 1,j] = 1,if(DP [i,j] == 1 || DP [i,j-A [i + 1]] == 1)

      否则,DP [i + 1,j] = 0。

      不要忘记在第一时间将表初始化为0。这解决了边界和无关紧要的情况。

      1. 计算您想要的值

        通过自下而上的实施,您最终可以填写整个表格。

      2. 现在,事情变得容易了。您只需要在表中找到与M值最接近的值。

        这里,只需要处理DP [n] [j],因为n覆盖了整个集合。找到距离M最近的j,其值为1.

        时间复杂度为O(kn),因为你总共迭代k * n次。