Python 背包问题,但允许过度填充

Python 背包问题,但允许过度填充,python,knapsack-problem,Python,Knapsack Problem,假设我有5个项目(名称、大小、值),如下所示: ("ITEM01", 100, 10000) ("ITEM02", 24, 576) ("ITEM03", 24, 576) ("ITEM04", 51, 2500) ("ITEM05", 155, 25) 我必须得到最接近的匹配,总尺寸为150(每个项目只能添加一次) 这与背包问题非常相似,但并不完全相同,因为在这种情况下,我的首选解决方案是ITEM01,ITEM04,总大小为151(背包问题将阻止我将大小设置为150,从而给出总大小为148的

假设我有5个项目(名称、大小、值),如下所示:

("ITEM01", 100, 10000)
("ITEM02", 24, 576)
("ITEM03", 24, 576)
("ITEM04", 51, 2500)
("ITEM05", 155, 25)
我必须得到最接近的匹配,总尺寸为150(每个项目只能添加一次)

这与背包问题非常相似,但并不完全相同,因为在这种情况下,我的首选解决方案是
ITEM01
ITEM04
,总大小为151(背包问题将阻止我将大小设置为150,从而给出总大小为148的
ITEM01
ITEM02
ITEM03


这个问题有名字吗?(它仍然是组合优化吗?我正在寻找一个python解决方案,但是如果我知道我要寻找的东西的名称,它会有所帮助。

您可以尝试使用动态编程来实现它

dp[k]
等于项目列表,大小之和等于
k
。对于
k>0
,最初
d[0]=[]
dp[k]=None
。列表的大小可能受到所有元素大小总和的限制,我们称之为
s

该算法所做的是针对每个
i=S
i=0
,并检查
dp[i]!=无
,这意味着我们可以选择大小总和等于
i
的项目。这些项目在列表中
dp[i]
。让我们观察一下,我们可以将当前的
添加到该列表中,并且有一组项的总和等于
i+item.size
。所以我们分配
dp[i+item.size]=dp[i]+[item]
。处理完所有项目后,我们只需从所需的大小总和开始,然后双向查找最接近的匹配项

代码:

但是,此解决方案的复杂性是
O(n*S)
,其中
n
是项目数,
S
是大小之和,因此在某些情况下可能太慢。此解决方案中可以改进的是
S
常数。例如,您可以将
S
设置为
2*期望值总和
,因为我们保证我们可以在
[0,2*期望值总和]
中获取一组大小总和为的项目(可能是一个总和为
0
的空集)。如果您想至少购买一件物品,您可以购买
S=max(最小物品大小,2*所需总和-最小物品大小)
其中
min物品大小
是所有物品的最小尺寸

编辑

哦,您还希望在两个组合同样接近所需大小时获得最大值。然后,您必须稍微交替代码,以保持每个大小总和的最佳组合

即:

if dp[i] is not None and i + item[1] <= S:

如果dp[i]不是None,并且i+项[1]假设您有一个工作背包解算器和大量时间:

将每个项目的值设置为每个项目的重量,并解决容量为150的背包问题。这将为您提供小于目标的最大大小(在您的示例中为148)。因此,要考虑的最大尺寸是150 +(150 - 148)=152 < /P> 现在对150和152之间的每个整数再次求解。如果发现较小的差异(示例中为151),请停止,并使用原始项值求解值。如果范围很大,您也可以尝试二进制搜索


否则,解决容量为148和152的原始背包问题,并选择具有最大值的解决方案。

背包问题是在保持条件总重量的同时实现价值最大化。物品价值如何体现在目标函数中?@jakber我正在寻找(最佳值)组合给我一个最接近总尺寸的尺寸。但与背包不同的是,它可以超过总尺寸。@NPE尺寸是最重要的-目标是最接近总尺寸150(+/-)。在该值最大化之后(即如果两个组合的值相等接近150,则选择较高的值组合)。@jakber我认为他的限制条件是最小值(|总|重量容量|),非常感谢。是的,就我目前所知,这很好地工作(通过编辑)。它可能会减慢我可能不得不抛出的一些更大的数字,但目前它似乎是好的。是的,这也有效(遗憾的是,我不能接受两个答案),我已经开发了一些非常类似的东西。使用工作背包解算器,我将其运行一次,使其达到我理想尺寸*1.1的最大尺寸,这样我就可以接受超过尺寸10%的值。然后我找到理想尺寸的最佳解决方案。在那之后,我反复地从理想尺寸向上增加最大尺寸,直到找到一个为止。然后,在做出最终选择之前,我可以比较两者。非常感谢你的投入。
[('ITEM01', 100, 10000), ('ITEM04', 51, 2500)]
if dp[i] is not None and i + item[1] <= S:
if dp[i] is not None and i + item[1] <= S and \
    (
        dp[i + item[1]] is None
        or
        sum(set_item[2] for set_item in dp[i]) + item[2]
            > sum(set_item[2] for set_item in dp[i + item[1]])
    ):