【问题标题】:Should this be solved using a subset sum algorithm是否应该使用子集和算法来解决
【发布时间】:2014-01-29 17:31:54
【问题描述】:

问题是让我找到一个列表的所有可能子集,这些子集加在一起(成对、单独或多个)将等于给定的数字。我已经阅读了很多关于子集和问题的内容,但不确定这是否适用于这个问题。

为了更详细地解释这个问题,我有一个允许我购买的最大重量糖果。 我知道我存储在一个列表中的十块不同糖果的重量

candy = [ [snickers, 150.5], [mars, 130.3], ......]
I can purchase at most max_weight = 740.5 grams EXACTLY.

因此,我必须找到与 max_weight 完全相等的所有可能的糖果组合。我将在 python 中编程。不需要确切的代码,只需要它是否是子集和问题以及如何进行的可能建议。

【问题讨论】:

  • 这被称为“背包问题”
  • 不是,乍一看可能是背包,但没有优化的价值。
  • 这看起来不像是背包问题。没有与糖果相关的价值,也没有重量的上限。权重似乎是一个精确的约束,而不是一个上限约束。所以我会说这个/是/子集和问题
  • 啊,我显然已经纠正了:P
  • 每种糖果可以购买多少个?如果只有一个,这是子集和。否则,这是一个更一般的整数线性规划问题。

标签: python algorithm recursion


【解决方案1】:

好的,这是一种利用 numpy 索引魔法的蛮力方法:

from itertools import combinations
import numpy as np

candy = [ ["snickers", 150.5], ["mars", 130.3], ["choc", 10.0]]

n = len(candy)
ww = np.array([c[1] for c in candy]) # extract weights of candys
idx = np.arange(n) # list of indexes

iidx,sums = [],[]
# generate all possible sums with index list
for k in range(n):
    for ii in combinations(idx, k+1):
        ii = list(ii) # convert tupel to list, so it can be used as a list of indeces
        sums.append(np.sum(ww[ii]))
        iidx.append(ii)
sums = np.asarray(sums)
ll = np.where(np.abs(sums-160.5)<1e-9)  # filter out values which match 160.5

# print results
for le in ll:
    print([candy[e] for e in iidx[le]])

【讨论】:

  • 正如 Niklas B. 指出的那样,它可能会更准确,而且我实际上意识到,如果我将每个权重和 max_weight 乘以 100 并解析为 int 就更容易了,这样就不会出现任何错误由于浮点不精确。这就是你的
  • 我没有完全理解这两行代码。你能不能帮帮我。对于组合中的 ii (idx, k+1): ii = np.ravel(ii)
  • 关于&lt;1-9,您是完全正确的- 1e-9 是任意但合理的选择。 combinations 返回一个元组,但 numpy 想要列表或 np.arrays 作为索引集。 np.ravel 是正确转换的一种可能性。更新代码以使用list()
【解决方案2】:

这正是子集和问题。你可以使用a dynamic programming approach to solve it

【讨论】:

  • 请注意,我们需要乘以一个公约数以使所有权重成为整数。 100 对于这个输入似乎已经足够了,但是使用不精确的浮点数来表示权重有点奇怪。
  • 哦,如果真的只有 10 个元素,蛮力可能是更好的选择,因为 2^10 = 1024 相当小
猜你喜欢
  • 2012-04-15
  • 2017-11-19
  • 1970-01-01
  • 2019-04-09
  • 2021-01-14
  • 1970-01-01
  • 1970-01-01
  • 2019-09-11
  • 2021-03-27
相关资源
最近更新 更多