假设我有一个数字“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。
用尽可能少的计算次数来做到这一点的最佳方法是什么?
假设我有一个数字“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。
用尽可能少的计算次数来做到这一点的最佳方法是什么?
这看起来像是“子集总和”(参见:http ://en.wikipedia.org/wiki/Subset_sum_problem )问题的一个变体,已知它是 NP 完全的,所以很遗憾很可能不会有任何聪明的算法无论如何,在最坏的情况下,它的运行速度会比项目数量的指数更快。
如果要检查的项目不多(大约 10 个左右),您可以尽快尝试深度优先搜索修剪分支。
如果有更多的项目很可能要检查而不是搜索最佳解决方案,那么您最好尝试找到一个稍微好的近似值。
假设所有数字都是正整数,可以按照 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