我需要在列表中找到数字,这些数字构成一个特定的总数:
Sum: 500
Subtotals: 10 490 20 5 5
In the end I need: {10 490, 490 5 5}
你怎么称呼这类问题?是否有算法有效地解决它?
答案 0 :(得分:3)
这是Knapsack problem,它是NP完全问题,即没有已知的有效算法。
答案 1 :(得分:1)
假设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。如果问题的规模足够小,您也可以考虑动态编程:
如果在最终的集合中没有Sum,那么就没有解决方案。否则,您将Sum的解回溯为0,检查先前的集合是否包含[value]和[value-subtotal] 例如:
(10,490,20,5,5)
设定:
(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}。