数字子集的总和

时间:2013-03-26 19:24:01

标签: algorithm math lua knapsack-problem

假设我有一个数字'n'和一个数字表。我想在表格中选择最多四个数字,这四个数字的总和将是与n最接近的匹配。给定表的长度'L',它必须经历的组合数是(6 * L + 11 * L ^ 2 + 6 * L ^ 3 + L ^ 4)/ 24.

离。假设我有变量

n = 100

和一组数字

t = {86, 23, 19, 8, 42, 12, 49}

鉴于此列表,最接近的四个与n的组合是49 + 23 + 19 + 8 = 99。

以最少的计算次数执行此操作的最佳方法是什么?

2 个答案:

答案 0 :(得分:2)

这看起来像是'子集和'的变体(参见:http://en.wikipedia.org/wiki/Subset_sum_problem)问题已知是NP完整的,所以不幸的是很可能没有任何在最糟糕的情况下,聪明的算法将以更快的速度运行,以指数的项目数量。

如果要检查的项目不多(约10个左右),您可以尽快尝试深度搜索修剪分支。

如果要检查的项目更多,而不是搜索最佳解决方案,您可能最好尝试找到一个更好的近似值。

答案 1 :(得分:0)

假设所有数字都是正整数,可以像Yexo指出的那样完成:

local n = 100
local t = {86, 23, 19, 8, 42, 12, 49}
local max_terms = 4
-- best[subset_size][terms][k] = {abs_diff, expr}
local best = {[0] = {}}
for k = 1, n do best[0][k] = {k, ''} end
for terms = 0, max_terms do best[terms] = best[0] end
for subset_size = 1, #t do
   local new_best = {}
   for terms = subset_size == #t and max_terms or 0, max_terms do
      new_best[terms] = {}
      for k = subset_size == #t and n or 1, n do
         local b0 = best[terms][k]
         local diff = k - t[subset_size]
         local b1 = terms > 0 and (
            diff > 0 and {
               best[terms-1][diff][1],
               best[terms-1][diff][2]..'+'..t[subset_size]
            } or {math.abs(diff), t[subset_size]}
         ) or b0
         new_best[terms][k] = b1[1] < b0[1] and b1 or b0
      end
   end
   best = new_best
end
local expr = best[max_terms][n][2]:match'^%+?(.*)'
print((loadstring or load)('return '..expr)()..' = '..expr)

-- Output
99 = 23+19+8+49