集合中加权元素的组合,其中加权和等于固定整数(在Python中)
我想找到一个集合中加权元素的所有可能组合,其中它们的权重总和恰好等于给定的权重 W
假设我想从集合中选择 k 个元素 { 'A', 'B', 'C', 'D', 'E' }
其中 权重 = {'A':2, 'B':1, 'C':3, ' D':2, 'E':1}
和 W = 4
。
那么这会产生: <代码>('A','B','E') ('广告') ('公元前') ('B'、'D'、'E') ('C','E')
我意识到蛮力方法是找到给定集合的所有排列(使用 itertools.permutations
)并拼接出前 k 个元素W 的加权和。但我每组至少处理 20 个元素,这在计算上会很昂贵。
我认为使用背包的变体会有所帮助,其中仅考虑重量(而不是价值),并且重量之和必须等于 W(不劣于)。
我想在 python 中实现这个,但是任何 cs 理论提示都会有帮助。优雅加分!
I would like to find all the possible combinations of weighted elements in a set where the sum of their weights is exactly equal to a given weight W
Say I want to select k elements from the set { 'A', 'B', 'C', 'D', 'E' }
where weights = {'A':2, 'B':1, 'C':3, 'D':2, 'E':1}
and W = 4
.
Then this would yield :('A','B','E')
('A','D')
('B','C')
('B','D','E')
('C','E')
I realize the brute force way would be to find all permutations of the given set (with itertools.permutations
) and splice out the first k elements with a weighted sum of W. But I'm dealing with at least 20 elements per set, which would be computationally expensive.
I think using a variant of knapsack would help, where only weight (not value) is considered and where the sum of weights must be equal to W (not inferior).
I want to implement this in python but any cs-theory hints would help. Bonus points for elegance!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
循环遍历所有n!排列太昂贵了。相反,生成所有 2^n 个子集。
组
可以通过将列表理解的返回部分更改为 tuple(sorted(x)) 或替换
中的
用 1 来list
调用来将其转换为排序元 powerset排序
。Looping through all n! permutations is much too expensive. Instead, generate all 2^n subsets.
yields
This can be converted to sorted tuples by changing the return part of the list comprehension to
tuple(sorted(x))
, or by replacing thelist
call inpowerset
with one tosorted
.您对此类集合中的项目数量有上限吗?如果您这样做,并且最多约为 40 个,则 "meet-in-the -middle”算法,如 Knapsack 上的维基百科页面 可以非常简单,并且比暴力计算的复杂性要低得多。
注意:使用比 Python 字典更节省内存的数据结构,这也适用于更大的集合。高效的实现应该能够轻松处理大小为 60 的集合。
下面是一个示例实现:
Do you have an upper bound on the number of items in such sets? If you do and it is at most about 40, then the "meet-in-the-middle" algorithm as described in the Wikipedia page on Knapsack can be quite simple and has significantly lower complexity than a brute-force computation.
Note: Using a more memory-efficient data structure than a Python dict, this could also work on larger sets. An efficient implementation should easily handle sets of size 60.
Here is a sample implementation:
(在某种程度上)有效地做到这一点的技巧是使用前 k 个项目创建具有相同权重的元素集。
从 k=0 处的空集开始,然后使用 k-1 中的组合创建 k 的组合。除非你可以有负权重,否则你可以修剪总权重大于 W 的组合。
以下是使用示例的结果:
comb[k,w] 是使用前 k 个元素具有总权重 w 的元素集.
大括号用于集合。
S+e 是通过将元素 e 添加到 S 的每个成员而创建的集合的集合。
答案是comb[5,4],它简化为:
给出所有组合。
The trick to doing this (somewhat) efficiently is to create sets of elements that have the same weight using the first k items.
Start with an empty set at k=0, then create your combinations for k using combinations from k-1. Unless you can have negative weights, you can prune combinations with a total weight greater than W.
Here is how it plays out using your example:
comb[k,w] is the set of elements having a total weight w using the first k elements.
Braces are used for sets.
S+e is the set of sets created by adding element e to each member of S.
The answer is then comb[5,4], which simplifies to:
Giving all the combinations.