如何找出哪个小计构成总和?

时间:2013-07-26 09:39:46

标签: algorithm sum subtotal

我需要在列表中找到数字,这些数字构成一个特定的总数:

Sum: 500

Subtotals: 10 490 20 5 5

In the end I need: {10 490, 490 5 5}

你怎么称呼这类问题?是否有算法有效地解决它?

2 个答案:

答案 0 :(得分:3)

这是Knapsack problem,它是NP完全问题,即没有已知的有效算法。

答案 1 :(得分:1)

  1. 这是背包问题。
  2. 在最坏的情况下,使用N个小计,可以有O(2 ^ N)个解,所以在最坏的情况下任何算法都不会比这更好(因此,问题不属于NP类)在所有)。
  3. 假设Subtotals数组中没有非正元素,并且任何元素都不大于Sum。我们可以对小数组进行排序,然后构建尾数组数组,最后添加0。在您的示例中,它将如下所示:

    Subtotals:   (490, 20, 10,  5, 5)  
    PartialSums: (530, 40, 20, 10, 5, 0)
    

    现在任何"余额" S,位置i和"当前列表"我们有问题E(S,i,L):
    E(0,i,L)=(打印L)。
    E(S,i,L)| (PartialSums [i]< S)=(没有)。
    E(S,i,L)= E(S,i + 1,L),E(S-Subtotals [i],j,L || Subtotals [i]),其中j是Subtotals较小的第一个元素的索引大于或等于(S-Subtotals [i])或i + 1,以较大者为准 我们的问题是E(Sum,0,{})。

    当然,重复有问题(如果列表中有另外490个数字,此算法将输出4个解决方案)。如果那不是你所需要的,那么使用数组(值,多重性)可能有所帮助。

    P.S。如果问题的规模足够小,您也可以考虑动态编程:

    1. 从集合{0}开始。创建等于小计数组的集合数组。
    2. 对于每个小计,通过添加小计值从先前的集合创建新集合。删除大于Sum的所有元素。将其与之前的集合合并(它基本上是所有可能总和的集合)。
    3. 如果在最终的集合中没有Sum,那么就没有解决方案。否则,您将Sum的解回溯为0,检查先前的集合是否包含[value]和[value-subtotal] 例如:

      (10,490,20,5,5)

    4. 设定:

      (0)
      (0, 10)
      (0, 10, 490, 500)
      (0, 10, 20, 30, 490, 500) (510, 520 - discarded)
      (0, 5, 10, 15, 20, 25, 30, 35, 490, 495, 500)
      (0, 5, 10, 15, 20, 25, 30, 35, 40, 490, 495, 500)
      

      从上一组:前一组中的[500-5],前一组中的[495-5],[490-20]不在前一组([490]中),[490-490]为0,结果为回答{5,5,490}。

相关问题