我有一个问题陈述说:如果你有一个元素数组{x1,x2,x3,... x10},找到元素的组合,使它只是总和超过一个阈值(比如阈值)价值是100)。
因此,如果存在x2+x5+x8 = 105
,x3+x5+x8=103
和x4+x5 = 101
等组合,则算法应输出X4,X5。
背包算法发出的值接近但在阈值的较小一侧(此处为100)。我想要相反的,即所选元素的最小总和大于100。
是否有任何算法集或任何可能解决此问题的算法的特殊情况?
答案 0 :(得分:1)
我首先要注意你要求的最小值严格大于某个目标。通常"严格大于"并且"严格低于"约束比"大于或等于"更难。或者"小于或等于"限制。如果你有所有整数值,那么你可以简单地翻译你的约束"总和超过100"到"总和大于或等于101"。我假设你已经为问题的其余部分做了这样的转变。
一种方法是将此视为整数优化问题,其中每个数字的二元决策变量y_i
是否包含它。然后我们的目标是最小化数字的总和,可以建模为:
min x_1*y_1 + x_2*y_2 + ... + x_n*y_n
这种情况下的约束是数字之和至少为100:
x_1*y_1 + x_2*y_2 + ... + x_n*y_n >= 100
一般来说,这是一个难题(请注意,它至少与子集和问题一样难,这是NP完全的)。但是,现代优化求解器可能对您的问题实例足够有效。
要测试此问题的自由求解器的可伸缩性,请考虑使用R中的lpSolve
包进行以下实现(如果问题可行则返回选定的子集,否则返回NA
):< / p>
library(lpSolve)
min.subset <- function(x, min.sum) {
mod <- lp("min", x, matrix(x, nrow=1), ">=", min.sum, all.bin=TRUE)
if (mod$status == 0) {
which(mod$solution >= 0.999)
} else {
NA
}
}
min.subset(1:10, 43.5)
# [1] 2 3 4 5 6 7 8 9
min.subset(1:10, 88)
# [1] NA
为了测试可扩展性,我将从n
中随机选择[1, 2, ..., 1000]
个元素,将目标总和设置为元素总和的一半。运行时间是:
n=100
,它在0.01秒内运行n=1000
,它在0.1秒内运行n=10000
,它以8.7秒的速度运行看起来你可以解决超过10k个元素(使用所选分布)的这个问题而没有太多的计算挑战。如果你的问题对于我在这里使用过的免费求解器来说太大了,你可以考虑使用Gurobi或cplex,这两个商业解决方案可以免费学习,但不是免费的。
答案 1 :(得分:1)
假设X
是所有x_i
的总和。然后等效地,您要求的x_i
的最小子集最多总计X - 100
(因为这些x_i
的补充将是您问题的最佳解决方案)。因此,所有背包理论都可以在这里应用。
在实践中(非常大的实例),我建议使用this形式的Nemhauser-Ullman泛化,它可以解决数百万个对象的实例。