多重背包/装箱算法

Posted

技术标签:

【中文标题】多重背包/装箱算法【英文标题】:Multiple Knapsack/Bin-packing algorithm 【发布时间】:2018-04-15 17:57:00 【问题描述】:

问题如下:

你有一个包含 n 个对象的堆栈,每个对象的体积为 Vi。你也有 k 个盒子,它们都有一个固定的体积 V。对于堆栈顶部的每个对象,如果该对象适合当前的盒子,你必须在将它放入盒子和移动到下一个对象之间做出选择,或关闭此框并跳至下一个框。

每个盒子的成本定义为盒子里剩下的体积的平方。

您的目标是将所有对象放入盒子中,并最小化所有盒子成本的总和。

我应该使用什么算法(我在想一些图表)?

【问题讨论】:

查看en.wikipedia.org/wiki/Knapsack_problem#Solving @yalpsideman 不太可能有解决方案,因为这个问题是一个相当受限的版本:考虑对象的顺序是固定的。 【参考方案1】:

这可以通过动态规划来解决。

状态可以是(满箱数,取走物数)。

函数是达到这种状态的最小总成本。

可以如下进行转换。 让我们从状态(box, obj) 开始,当我们已经知道实现它的最佳方法时,成本为f[box][obj]。 取对象编号obj+1obj+2...,直到它们的体积总和v[i]超过盒子容量V

在获取每个新对象i之后,如果我们关闭当前框会发生什么? 我们已经达到状态(box + 1, i),成本是f[box][obj]加上(V减去体积之和v[obj+1]v[obj+2]...v[i])的平方。 如果这是迄今为止实现(box+1, i) 状态的最佳方式,请将其分配给f[box+1][i]

基地是f[0][0] = 0

答案是f[k][n],其中k 是盒子的数量,n 是对象的数量。

在伪代码中:

f = array [0..k] [0..n] of integers
fill f[][] with infinity
f[0][0] = 0
for box = 0, 1, ..., k-1:
    for obj = 0, 1, ..., n:
        if f[box][obj] < infinity:
            left = V
            f[box+1][obj] = min (f[box+1][obj], f[box][obj] + V*V)
            for i = obj+1, obj+2, ..., n:
                left -= v[i]
                if left < 0:
                    break
                f[box+1][i] = min (f[box+1][i], f[box][obj] + left*left)
answer = f[k][n]

【讨论】:

你的回答真的很好,但是我觉得我表达的问题不够好……我忘了说最后的成本也考虑了空箱。示例:第 5 卷的 2 个对象和第 10 卷的 2 个盒子,通过每个盒子分配一个对象,可能的最低成本是 50。你认为我们可以调整你的算法吗? 啊,对不起,我错过了盒子数量为固定整数的部分K。那么答案就是f[K][n]。我们必须添加一个对应于空框的转换,这是在内部i 循环之前添加的一行。我会在一两个小时内编辑代码。 @leodaher 编辑了答案以完全使用k 框。

以上是关于多重背包/装箱算法的主要内容,如果未能解决你的问题,请参考以下文章

动态规划-多重背包问题

多重背包

dp背包问题/01背包,完全背包,多重背包,/coin change算法求花硬币的种类数

分弹珠(动态规划+多重背包)- HDU 1059

[算法]动态规划 多重背包 二进制优化

动态规划入门——经典的完全背包与多重背包问题