【问题标题】:Sum of a subset of numbers数字子集的总和
【发布时间】:2013-03-28 10:45:18
【问题描述】:

假设我有一个数字“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 的 4 组合是 49 + 23 + 19 + 8 = 99。

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

【问题讨论】:

  • 在正常的背包问题中,您选择的最大物品数量没有限制,而在您的问题中似乎限制为四个。我仍然会使用与 0/1 背包(动态编程)相同的方法。使用这种方法,您可以在O(4nL) 中解决它,只要您在 t 中获得多个项目,就会快很多。
  • 如果穷举搜索算法太慢,请尝试branch and bound,这样您无需尝试就可以忽略大量子集。阅读第 13 章statslab.cam.ac.uk/~rrw1/mor/s2010a4.pdf
  • 问题最多显示四个数字。 49 + 42 + 8 = 99。

标签: algorithm math lua knapsack-problem


【解决方案1】:

这看起来像是 'subset sum'(参见:http://en.wikipedia.org/wiki/Subset_sum_problem)问题的变体,已知它是 NP 完全的,所以很遗憾很可能不会有任何聪明的算法在最坏的情况下,它的运行速度会比项目数量的指数更快。

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

如果有更多的项目需要检查,而不是寻找最佳解决方案,您最好尝试找到一个比较好的近似值。

【讨论】:

  • 他的问题被限制了。有一个简单的 O(n^4) 解决方案,只需枚举大小最大为 4 的每个子集。
  • 你是对的。似乎我错过了固定数量的项目。
【解决方案2】:

假设所有数字都是正整数,可以按照 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

【讨论】:

  • 'for k = 1, n do' 看起来甚至比遍历所有可能的组合效率更低。 n 可能是 1000 万。
  • 有没有办法做到这一点,其中计算结果所花费的工作不依赖于 n,它可以是任何数字?
  • 如果数字集的大小是 1000,那么我的解决方案大约需要 420 亿次迭代。我需要一个解决方案,能够以尽可能少的计算来处理这么多的数字。
  • @Waffle - 这就是为什么最好使用 O(nL) 算法,而不是 O(L^4)。
  • 该算法的链接在哪里,它是否适用于我正在尝试做的事情?我想找到最多四个中最接近的子集,无论是否准确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
  • 2017-03-17
  • 1970-01-01
相关资源
最近更新 更多