Python 将少量包装装入固定数量的箱子中

Python 将少量包装装入固定数量的箱子中,python,algorithm,Python,Algorithm,我有一份包裹尺寸的清单。最多有5种不同的尺寸,可能会出现几次(棘手的一个,真的不确定最优解。下面是一个迭代所有可能的组并在第一个解处停止的解。这应该是一个最小余数解,因为我们首先迭代所有解,没有余数 它还将解决方案作为第一个容器中的所有内容进行迭代,可以排除这些内容以获得更快的结果 import numpy as np def int_to_base_list(x, base, length): """ create a list of length length that expre

我有一份包裹尺寸的清单。最多有5种不同的尺寸,可能会出现几次(棘手的一个,真的不确定最优解。下面是一个迭代所有可能的组并在第一个解处停止的解。这应该是一个最小余数解,因为我们首先迭代所有解,没有余数

它还将解决方案作为第一个容器中的所有内容进行迭代,可以排除这些内容以获得更快的结果

import numpy as np

def int_to_base_list(x, base, length):
    """ create a list of length length that expresses a base-10 integer
        e.g. binary: int2list(101, 2, 10) returns array([0, 0, 0, 1, 1, 0, 0, 1, 0, 1])
    """
    placeholder = np.array([0] * length)  # will contain the actual answer
    for i in reversed(range(length)):
        # standard base mathematics, see http://www.oxfordmathcenter.com/drupal7/node/18
        placeholder[i] = x % base  
        x //= base
    return placeholder

def get_groups(packages, max_diff_sum, number_of_bins):
    """ Get number_of_bins packaging groups that differ no more than max_diff_sum
        e.g. 
        [5, 5, 5, 5, 5, 5, 10, 11] with 2, 3 gives [5,5,5], [10,5], [11,5]
        [5, 10, 12] with 2, 2 gives [10], [12]
        [2, 6, 12] with 2, 3 gives [2], [], []

        We approach the problem by iterating over group indices, so the first
        example above has solution [0 0 0 1 2 3 1 2] with the highest number being
        the 'remainder' group. 
    """
    length = len(packages)
    for i in range((number_of_bins + 1)**length - 1):  # All possible arrangements in groups 
        index = int_to_base_list(i, number_of_bins + 1, length)  # Get the corresponding indices
        sums_of_bins = [np.sum(packages[index==ii]) for ii in range(number_of_bins)]
        if max(sums_of_bins) - min(sums_of_bins) <= max_diff_sum:  # the actual requirement 
            # print(index)
            break
    groups = [packages[index==ii] for ii in range(number_of_bins)] 
    # remainder = packages[index==number_of_bins+1]
    return groups


棘手的一点是,确实不确定最优解。下面是一个只迭代所有可能的组并在第一个解处停止的解。这应该是一个最小余数解,因为我们首先迭代所有解,没有余数

它还将解决方案作为第一个容器中的所有内容进行迭代,可以排除这些内容以获得更快的结果

import numpy as np

def int_to_base_list(x, base, length):
    """ create a list of length length that expresses a base-10 integer
        e.g. binary: int2list(101, 2, 10) returns array([0, 0, 0, 1, 1, 0, 0, 1, 0, 1])
    """
    placeholder = np.array([0] * length)  # will contain the actual answer
    for i in reversed(range(length)):
        # standard base mathematics, see http://www.oxfordmathcenter.com/drupal7/node/18
        placeholder[i] = x % base  
        x //= base
    return placeholder

def get_groups(packages, max_diff_sum, number_of_bins):
    """ Get number_of_bins packaging groups that differ no more than max_diff_sum
        e.g. 
        [5, 5, 5, 5, 5, 5, 10, 11] with 2, 3 gives [5,5,5], [10,5], [11,5]
        [5, 10, 12] with 2, 2 gives [10], [12]
        [2, 6, 12] with 2, 3 gives [2], [], []

        We approach the problem by iterating over group indices, so the first
        example above has solution [0 0 0 1 2 3 1 2] with the highest number being
        the 'remainder' group. 
    """
    length = len(packages)
    for i in range((number_of_bins + 1)**length - 1):  # All possible arrangements in groups 
        index = int_to_base_list(i, number_of_bins + 1, length)  # Get the corresponding indices
        sums_of_bins = [np.sum(packages[index==ii]) for ii in range(number_of_bins)]
        if max(sums_of_bins) - min(sums_of_bins) <= max_diff_sum:  # the actual requirement 
            # print(index)
            break
    groups = [packages[index==ii] for ii in range(number_of_bins)] 
    # remainder = packages[index==number_of_bins+1]
    return groups

以下是一个使用以下方法的解决方案:

来自纸浆进口*
套餐=[18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,65,65]
垃圾箱的数量=3
箱子=范围(1,箱子数量+1)
项目=范围(0,长度(包))
x=LpVariable.dicts('x',[(i,b)表示项目中的i,b表示容器中的b],0,1,LpBinary)
y=LpVariable('y',0,2,LpInteger)
prob=LpProblem(“料仓包装”,LpMinimize)
#最大化放置在箱子中的物品
prob.setObjective(LPAffiineExpression([(x[i,b],-3)表示料仓中b的项目中的i]+[(y,1)])
#每件物品最多放在一个箱子里
对于项目中的i:
prob+=lpSum([x[i,b]表示容器中的b])=0
如果b!=垃圾箱的数量:#最后一个垃圾箱是最高的
prob+=LpAffineExpression([(x[i,容器数量],项目中i的包[i])+[(x[i,b],-项目中i的包[i])>=0
#最高和-最低和这里有一个解决方案,使用:

来自纸浆进口*
套餐=[18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,65,65]
垃圾箱的数量=3
箱子=范围(1,箱子数量+1)
项目=范围(0,长度(包))
x=LpVariable.dicts('x',[(i,b)表示项目中的i,b表示容器中的b],0,1,LpBinary)
y=LpVariable('y',0,2,LpInteger)
prob=LpProblem(“料仓包装”,LpMinimize)
#最大化放置在箱子中的物品
prob.setObjective(LPAffiineExpression([(x[i,b],-3)表示料仓中b的项目中的i]+[(y,1)])
#每件物品最多放在一个箱子里
对于项目中的i:
prob+=lpSum([x[i,b]表示容器中的b])=0
如果b!=垃圾箱的数量:#最后一个垃圾箱是最高的
prob+=LpAffineExpression([(x[i,容器数量],项目中i的包[i])+[(x[i,b],-项目中i的包[i])>=0


#最高和-最低和我不确定我是否理解。为什么
[11,5],[10,5,5],[5,5]
这不是一个更好的解决方案吗?你的描述表明包裹大小被忽略了。你的意思是说箱子大小在0到20之间变化吗?@Roelant我的意思是箱子里的东西的大小变化不应该超过2。所以我的例子的大小是16,15,15,你的是16,20,15,而20-15大于2。@alexis我已经试着澄清,th垃圾箱的大小并不重要,只是垃圾箱中包裹大小的总和。等等,你是想说每个垃圾箱与下一个垃圾箱的总大小差异需要有界?所以每个垃圾箱可以任意变大,只要与下一个垃圾箱的差异很小。这一点都不清楚(实际上仍然不清楚)。一般来说,人们希望限制是每个箱子的最大容量。我不知道我是否理解。为什么
[11,5],[10,5,5],[5,5]
这不是一个更好的解决方案吗?你的描述表明包裹大小被忽略了。你的意思是说箱子大小在0到20之间变化吗?@Roelant我的意思是箱子里的东西的大小变化不应该超过2。所以我的例子的大小是16,15,15,你的是16,20,15,而20-15大于2。@alexis我已经试着澄清,th垃圾箱的大小并不重要,只是垃圾箱中包裹大小的总和。等等,你是想说每个垃圾箱与下一个垃圾箱的总大小差异需要有界?所以每个垃圾箱可以任意变大,只要与下一个垃圾箱的差异很小。这一点都不清楚(实际上仍然不清楚)。通常情况下,人们希望限制是每个垃圾箱的最大容量。我会尝试一下,可能不会在星期五之前(现在开始),然后再报告。速度足够快,最多可以通过50个(可能更少)最多6箱包装?@DonQuiKong这意味着6**50,所以noI尝试了果肉解决方案,而这一个有40包和6箱,果肉版本运行了。我会尝试这个,可能不会在周五之前(现在开始),然后报告。足够快,可以通过50箱(可能更少)最多6箱包装?@DonQuiKong这意味着6**50,所以noI尝试了纸浆溶液,而这一个有40包和6箱,纸浆版本运行这太棒了!非常感谢!是否可以轻松地最小化值(大小)在不损失性能的情况下,考虑到剩余的部分,甚至是两个存储箱之间的差异,这将是一个很好的特性;-)@DonQuiKong目前脚本正在最小化箱子中遗漏的物品数量,您可能希望最小化遗漏物品的大小之和?使用此模型无法最小化箱子之间的差异,因为我们只能选择模仿一个函数,其余的都是约束。但是,您可以轻松地执行以下操作:从0循环到2,并运行代码,对值为的容器之间的差异进行约束,并解决这3个问题中的每一个问题,然后比较结果以满足您的需要。此外,我还发现输入反向排序的列表就可以了。(示例:')[18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,65,65]"返回"箱[[65,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18]]和剩余的[65]",但是如果输入是sor
bins = [11,5],[10,5],[5,5,5]
remaining = [5]
packages = [5,10,12]
number_of_bins = 2
bins = [12],[10]
remaining = [5]
bins = [12],[10,5]
packages = [2,10,12]
number_of_bins = 3
bins = [2],[],[]
remaining = [12,10]
import numpy as np

def int_to_base_list(x, base, length):
    """ create a list of length length that expresses a base-10 integer
        e.g. binary: int2list(101, 2, 10) returns array([0, 0, 0, 1, 1, 0, 0, 1, 0, 1])
    """
    placeholder = np.array([0] * length)  # will contain the actual answer
    for i in reversed(range(length)):
        # standard base mathematics, see http://www.oxfordmathcenter.com/drupal7/node/18
        placeholder[i] = x % base  
        x //= base
    return placeholder

def get_groups(packages, max_diff_sum, number_of_bins):
    """ Get number_of_bins packaging groups that differ no more than max_diff_sum
        e.g. 
        [5, 5, 5, 5, 5, 5, 10, 11] with 2, 3 gives [5,5,5], [10,5], [11,5]
        [5, 10, 12] with 2, 2 gives [10], [12]
        [2, 6, 12] with 2, 3 gives [2], [], []

        We approach the problem by iterating over group indices, so the first
        example above has solution [0 0 0 1 2 3 1 2] with the highest number being
        the 'remainder' group. 
    """
    length = len(packages)
    for i in range((number_of_bins + 1)**length - 1):  # All possible arrangements in groups 
        index = int_to_base_list(i, number_of_bins + 1, length)  # Get the corresponding indices
        sums_of_bins = [np.sum(packages[index==ii]) for ii in range(number_of_bins)]
        if max(sums_of_bins) - min(sums_of_bins) <= max_diff_sum:  # the actual requirement 
            # print(index)
            break
    groups = [packages[index==ii] for ii in range(number_of_bins)] 
    # remainder = packages[index==number_of_bins+1]
    return groups
packages = np.array([5, 5, 5, 5, 5, 5, 10, 11])
max_diff_sum = 2
number_of_bins = 3
get_groups(packages, max_diff_sum, number_of_bins)

>> [array([5, 5, 5]), array([ 5, 10]), array([ 5, 11])]
packages = np.array([5,10,12])
max_diff_sum = 2
number_of_bins = 2
get_groups(packages, max_diff_sum, number_of_bins)

>> [array([10]), array([12])]
from pulp import *

packages = [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 65, 65, 65]
number_of_bins = 3
bins = range(1, number_of_bins + 1)
items = range(0, len(packages))

x = LpVariable.dicts('x',[(i,b) for i in items for b in bins],0,1,LpBinary)
y = LpVariable('y', 0, 2, LpInteger)
prob=LpProblem("bin_packing",LpMinimize)

#maximize items placed in bins
prob.setObjective(LpAffineExpression([(x[i,b], -3) for i in items for b in bins] + [(y, 1)]))

#every item is placed in at most 1 bin
for i in items:
    prob+= lpSum([x[i,b] for b in bins]) <= 1

for b in bins:
    if b != 1: # bin 1 is the one with lowest sum
        prob+= LpAffineExpression([(x[i,b], packages[i]) for i in items]  + [(x[i,1], -packages[i]) for i in items])  >= 0
    if b != number_of_bins: # last bin is the one with highest
        prob+= LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items]  + [(x[i,b], -packages[i]) for i in items])  >= 0

#highest sum - lowest sum <= 2 so every difference of bin sums must be under 2
prob += LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items]  + [(x[i,1], -packages[i]) for i in items]) <= 2  
prob += LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items]  + [(x[i,1], -packages[i]) for i in items]) == y

prob.solve()
print(LpStatus[prob.status])

for b in bins:
    print(b,':',', '.join([str(packages[i]) for i in items if value(x[i,b]) !=0 ]))
print('left out: ', ', '.join([str(packages[i]) for i in items if sum(value(x[i,b]) for b in bins) ==0 ]))