Algorithm 数的子集之和
假设我有一个数字'n'和一个数字表。我想在表中选择最多四个数字,这四个数字的总和将是与n最接近的匹配。给定表的长度“L”,它必须经过的组合数为(6*L+11*L^2+6*L^3+L^4)/24 假设我有这个变量Algorithm 数的子集之和,algorithm,math,lua,knapsack-problem,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} 在这个列表中,4到n的最接近组合是49+23+19+8=99 用尽可能少的计算次数来实现这一点的最佳方法是什么?这看起来像是已知的NP完全问题的“子集和”(见:)的一个变体,所以不幸的是,很
n = 100
还有一组数字
t = {86, 23, 19, 8, 42, 12, 49}
在这个列表中,4到n的最接近组合是49+23+19+8=99
用尽可能少的计算次数来实现这一点的最佳方法是什么?这看起来像是已知的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
local n=100
局部t={86,23,19,8,42,12,49}
局部最大项=4
--最佳[subset_size][terms][k]={abs_diff,expr}
局部最佳={[0]={}
对于k=1,n最好[0][k]={k',}结束
对于terms=0,max_terms做得最好[terms]=best[0]结束
对于子集_size=1,#t do
本地新_最佳={}
对于terms=subset_size==#t和max_terms或0,max_terms会
新的_最佳[术语]={}
对于k=subset_size==#t和n或1,n do
本地b0=最佳[术语][k]
局部差异=k-t[子集大小]
本地b1=术语>0和(
差值>0和{
最佳[条款-1][diff][1],
最佳[terms-1][diff][2]…'+'..t[子集大小]
}或者{math.abs(diff),t[subset_size]}
)或b0
新的[k]=b1[1]
在一个普通的背包问题中,你挑选的物品的最大数量是不受限制的,而在你的问题中,似乎只有四个。我仍然使用与0/1背包(动态规划)相同的方法。使用这种方法,您可以在O(4nL)中求解它。
一旦在t中获得了多于几个项,它的速度就会快得多。如果穷举搜索算法太慢,请尝试分支和绑定,这样您就可以不用尝试就消除子集的样本。阅读第13章,问题是最多四个数字。49+42+8=99.他的问题是有限的。有一个简单的O(n^4)解决方案,只需枚举大小为4的每个子集。你是对的。似乎我没有注意到有固定数量的项目。“对于k=1,n do”看起来甚至比检查所有可能的组合效率更低。n可能是1000万。有没有一种方法可以做到这一点,计算结果所做的工作不依赖于n,n可以是任何数字?如果数字集的大小是1000,那么我的解决方案需要大约420亿次迭代。我需要一个能用最少的计算量来处理这么多数字的解决方案。@Waffle-这就是为什么最好使用O(nL)算法,而不是O(L^4)。该算法的链接在哪里,它对我正在尝试的工作有效吗?我想找到最接近的可能的子集,最多四个,不管它是否精确。