无论子集大小如何,都可以创建独特的组合

Create unique combinations regardless of subset size

我正在做一个项目,无论子集大小如何,都需要在 Python 中获得独特的组合。

假设我有一个尺寸列表 [1,2,2,3,4,5] 和一个 8 的尺寸界限。我想要包含所有元素且没有重复的组合,这样每个组合的总和应小于或等于8. 另一个限制是sum和bound的减法应该是最小的。

例如,在这种情况下,答案应该是 [5,3] [4,2,2] [3,1] 这样,8 中的总浪费将是 4,即 (3+1)-8=4。

您可能需要 itertools.combinations 之类的东西,它将为您提供给定长度的子列表中所有可能的元素组合,而不会出现重复元素。

如果您想了解更多关于函数 combinations 的信息,我建议您也阅读 this


像这样的东西应该可以工作:

for i in range(8//min(myList)):
    for j in itertools.permutations(myList, i):
        if sum(j) == 8:
            print(j)

这样你就得到了 myList 的所有组合,并打印那些元素总和为 8 的组合。


这样的函数可能会有用:

def permutationsWithSum(myList: list[int], n: int):
    for i in range(n//min(myList)):
        for j in itertools.permutations(myList, i):
            if sum(j) == n:
                yield j

您可以使用递归函数来“强制”打包组合并从中获得最佳组合:

def pack(sizes,bound,subset=[]):
    if not sizes:                   # all sizes used
        yield [subset]              # return current subset
        return    
    if sizes and not subset:           # start new subset             
        i,m = max(enumerate(sizes),key=lambda s:s[1])
        subset = [m]                   # using largest size
        sizes  = sizes[:i]+sizes[i+1:] # (to avoid repeats)
    used = sum(subset)              
    for i,size in enumerate(sizes):    # add to current subset
        if subset and size>subset[-1]: # non-increasing order
            continue                   # (to avoid repeats)
        if used + size <= bound:
            yield from pack(sizes[:i]+sizes[i+1:],bound,subset+[size])
    if sizes:
        for p in pack(sizes,bound): # add more subsets
            yield [subset,*p]


def bestFit(sizes,bound):
    packs = pack(sizes,bound)
    return min(packs,key = lambda p : bound*len(p)-sum(sizes))

输出:

for p in pack([1,2,3,4,5],8):
    print(p,8*len(p)-sum(map(sum,p)))

[[5, 1], [4], [3, 2]] 9
[[5, 2, 1], [4, 3]] 1
[[5, 2], [4, 3, 1]] 1
[[5, 2], [4], [3, 1]] 9
[[5, 3], [4, 2, 1]] 1
[[5, 3], [4], [2, 1]] 9
[[5], [4, 1], [3, 2]] 9
[[5], [4, 2], [3, 1]] 9
[[5], [4, 3], [2, 1]] 9
[[5], [4], [3, 2, 1]] 9
[[5], [4], [3], [2, 1]] 17

print(*bestFit([1,2,3,4,5],8))
# [5, 2, 1] [4, 3]

print(*bestFit([1,2,3,4,5,6,7,8,9],18))
# [9, 1] [8, 4, 3, 2] [7, 6, 5]

随着您的尺寸列表变大,这将以指数级增长,但如果您只有非常小的输入,这可能就足够了