0-1 背包,因体重不足和超重情况而受到处罚

Posted

技术标签:

【中文标题】0-1 背包,因体重不足和超重情况而受到处罚【英文标题】:0-1 Knapsack with penalty for under and overweight cases 【发布时间】:2017-01-15 13:58:09 【问题描述】:

假设一个经典的 0-1 背包问题,但你可以让袋子上溢/下溢,但会受到一些惩罚。每个单元溢出(重量超过最大容量)扣除 X 利润,每个单元下溢(重量低于最大容量)扣除 Y 利润。

我想按利润与重量的比率对所有物品进行排序,然后尝试像正常的背包问题一样装满麻袋,然后对于剩余重量和物品,我通过考虑下溢和上溢来计算额外的利润。

此解决方案在某些情况下会失败,例如当有 3 件商品的重量分别为 30、20、10 和利润分别为 30、25、20 时。允许的最大权重为 39,下溢惩罚为 5,上溢惩罚为 10。

我的解决方案是像普通背包一样解决它,然后考虑惩罚,所以它给出了选择重量为 20,10 的物品的解决方案,但它不添加重量为 30 的物品,因为它的惩罚高于利润。最佳解决方案应该是选择权重30和10的项目。我现在唯一能想到的就是暴力破解,如果可能的话应该避免。如果有人能想到任何其他解决方案,那就太好了!

【问题讨论】:

当您的问题似乎与语言无关时,为什么要为 3 种不同的语言添加标签? 那些是我知道的语言。无论如何,现在编辑标签。 似乎从根本上比普通背包更难,因为在选择结束时评估惩罚的方式意味着在解决子问题时很难看出如何考虑惩罚.因此,动态规划方法似乎有问题。另一方面——也许只是将子问题解决为普通的背包问题,并在最后引入惩罚。 @john 这就是我尝试做的,但它对我不起作用。 我想知道为什么我的问题得到了 2 票否决嗯 【参考方案1】:

您可以将其分解为两个子问题,一个带有体重不足的惩罚,一个带有超重的惩罚。更具体地说,您可以通过解决两个不同的integer linear programming problems 来解决问题,并充分利用这两个解决方案:

假设您有n 的权重项w1,w2,...,wn 和值v1, v2, ..., vn。假设承重为C,不减重的处罚为A,超重的处罚为B(每单位)。

在这两个问题中,让二元决策变量为x1, ..., xn,表示是否选择了相应的项目。

问题 1)

max v1*x1 + v2*x2 + ... + vn*xn - A*(C - w1*x1 - w2*x2 - ... - wn*xn)

subject to

w1*x1 + w2*x2 + ... + wn*xn <= C

注意,通过代数,目标函数与仿射表达式相同

(v1 + A*w1)*x1 + ... + (vn + A*wn)*xn - A*C 

并在与最大化纯线性函数的相同值x1, ..., xn 处最大化

(v1 + A*w1)*x1 + ... + (vn + A*wn)*xn 

这个子问题可以使用任何 ILP 求解器来解决,或者就像一个普通的背包问题。

问题 2)

max v1*x1 + v2*x2 + ... + vn*xn - B*(w1*x1 + w2*x2 + ... + wn*xn - C)

subject to

w1*x1 + w2*x2 + ... + wn*xn >= C

这可以通过最大化线性目标函数来解决

(v1 - B*w1)*x1 + ... + (vn - B*wn)*xn 

同样,这可以使用任何 ILP 求解器来求解。这个问题不是背包问题,因为主约束中的不等式指向错误的方向,尽管可能有一些方法可以将其简化为背包问题。

编辑时。第二个问题也可以作为一个背包问题来解决——你决定哪些物品不包括在内。从包含所有内容的解决方案开始。如果这不可行(如果所有权重的总和不超过容量),那么你就完成了。问题1的解决方案是全局解决方案。除此以外。定义盈余,S,为

S = w1 + w2 + ... + wn - C

现在,解决以下背包问题:

weights: w1, w2, ..., wn //same as before
values: Bw1 - v1, Bw2 - v2, ..., BWn - vn
capacity: S

关于值的一句话:Bwi - vi 是衡量删除第 i 个对象有多少帮助(假设删除它会使您保持在原始容量之上,这样您就不需要考虑减持处罚)。一方面,它消除了部分惩罚,Bwi,但另一方面它带走了一些价值,vi

在你解决了这个背包问题之后——移除这些物品。剩下的就是问题2的解法了。

让我们看看这如何解决您的玩具问题:

weights: 30, 20, 10
values: 20, 25, 20
C: 39
A: 5  //per-unit underflow penalty
B: 10 //per-unit overflow penalty

对于问题1,解决以下背包问题:

weights: 30, 20, 10
values: 170, 125, 70  // = 20 + 5*30, 25 + 5*20, 20 + 5*10
C: 39

这有解决方案:包括 20、10,值为 195。就原始问题而言,其值为 195 - 5*39 = 0。这看起来有点奇怪,但就原始问题而言,使用的价值最后两项是 25 + 20 = 45,但它会让你落后 9 个单位,罚分 5*9 = 45 和 45 - 45 = 0

第二个问题:

weights: 30, 20, 10
values: 280, 175, 80  // = 10*30 - 20, 10*20 - 25, 10*10 - 20
S: 26  // = 30 + 20 + 10 - 39

这个问题的解决方案显然是选择20。这意味着不包含选择了20。这意味着对于第二个问题,我想包含权重为 30 和 10 的对象。

这样做的价值是(就原始问题而言)

20 + 20 - 10*1 = 30

由于 30 > 0(解 1 的值),这是整体最优解。

总结一下:你可以通过解决两个普通的背包问题找到两个候选解决方案,然后取两者中的一个来解决你的背包问题版本。如果您已经有一个解决背包问题的函数,那么编写另一个调用它两次、解释输出并返回最佳解决方案的函数应该不会太难。

【讨论】:

【参考方案2】:

您仍然可以使用标准动态编程。

    让我们计算从 0 到数组中所有元素的总和的所有 s 是否可以达到总和 s。这正是标准动态编程解决方案所做的。我们不在乎这里的惩罚。

    让我们遍历所有可达到的总和,并在考虑溢出(或不足)流量的情况下选择最佳的。

【讨论】:

这与暴力破解有何不同?标准背包的动态规划方法不会计算所有可达的s,而只会计算满足最优条件的那些。 你能用 c/c++ 编写代码吗?据我所知,您是在建议蛮力。

以上是关于0-1 背包,因体重不足和超重情况而受到处罚的主要内容,如果未能解决你的问题,请参考以下文章

如何在不因内存不足而导致应用程序崩溃的情况下擦除矢量元素?

WPF 内存不足异常

iOS:浏览器因内存不足而崩溃

背包问题

如何在 Flutter 中为文本着色

如何解决 J2ME 中的“应用程序因内存不足而意外退出”错误