【问题标题】:Find All Combinations of Numbers That Uniquely Sum to a Set of Numbers找到唯一和一组数字的所有数字组合
【发布时间】:2018-04-19 02:24:32
【问题描述】:

我有一个数字列表(源集),有人取了部分或全部这些数字并将它们随机相加以形成一个较小的数字集(目标集)。我有源集和目标集,但我需要弄清楚使用了什么组合。难点:我不能保证源集中的所有数字都用于制作目标集,也不能保证目标集中的所有数字都来自源集。这是一个简单的例子:

  • 源集 = 1,2,3,4,5
  • 目标集 = 3,8
  • 结果:
    • ResultSet1: Sum([1,2])=3 Sum([3,5])=8 NotFound([]) NotUsed([4])
    • ResultSet2: Sum([3])=3 Sum([1,2,5])=8 NotFound([]) NotUsed([4])
    • ResultSet3: Sum([1,3,4])=8 NotFound([3]) NotUsed([2,5])
  • 无效的答案:
    • InvalidSet1:Sum([1,2])=3 Sum([3])=3 Sum([3,5])=8 NotFound([]) NotUsed:[4]
      • 原因:源集中的每个数字只能用于在给定结果集中创建任何目标

我找到了一些很好的例子,可以在给定单个目标值的情况下推导上述内容,但是我找不到使用目标值数组而不是单个值的方法(不幸的是,我的编码技能没有提高到任务)。我最好的开始是this question,代码如下(请注意,我删除了 s >= target 检查以容纳我的数据):

def subset_sum(numbers, target, partial=[]):
    s = sum(partial)

    # check if the partial sum is equals to target
    if s == target: 
        print "sum(%s)=%s" % (partial, target)
    #if s >= target:
    #    return  # if we reach the number why bother to continue

    for i in range(len(numbers)):
        n = numbers[i]
        remaining = numbers[i+1:]
        subset_sum(remaining, target, partial + [n]) 

if __name__ == "__main__":
    subset_sum([1,2,3,4,5],4)

这将输出:

sum([1, 3])=4
sum([4])=4

我已经做出了一些勇敢的尝试来添加第二层递归以支持目标数组,但我不会因为将失败放在这里而让自己尴尬。

我了解上述代码存在局限性,我愿意接受基于此代码或全新代码的解决方案,并以几乎任何逻辑格式输出。 Python 是首选,但我几乎可以接受任何事情(注意:java 给我带来了荨麻疹)。

【问题讨论】:

    标签: python algorithm search combinations


    【解决方案1】:

    你的意思是这样的:

    In []:
    import itertools as it
    
    source = [1, 2, 3, 4, 5]
    targets = [3, 8]
    
    p = [[a for n in range(1, len(source)) for a in it.combinations(source, n) if sum(a) == t] for t in targets]
    [dict(zip(targets, a)) for a in it.product(*p) if len(sum(a, tuple())) == len(set(sum(a, tuple())))]
    
    Out[]:
    [{3: (3,), 8: (1, 2, 5)}, {3: (1, 2), 8: (3, 5)}]
    

    【讨论】:

    • 谢谢,但不完全是。在您的代码似乎单独输出目标数组每个成员的所有可能组合的地方,它与目标数组的其他成员互斥。我将尝试澄清我的 OP,但在这里说:如果您使用 1 和 2 来制作 3,那么您不能在该结果集中使用 1 或 2 来制作 8。使用您的输出格式,它将包括: Set1: {3: [(1, 2)], 8: [(3, 5)]} Set2: {3: [(3)], 8: [(1, 2, 5)]} Set3: {8: [(1, 3, 4)]} 等...
    • 如果数字非常低,那么您可以很容易地暴力破解 - 更新。
    • 您的输出看起来与我所追求的完全一样...但由于某种原因,我无法运行您的代码(问题可能在我的键盘和椅子之间)。我可以通过在末尾添加 print (p) 来获得一些输出,但这不是正确的结果: [[(3,), (1, 2)], [(3, 5), (1, 2, 5), (1, 3, 4)]]
    • 为字典列表赋值,例如result = [dict(zip(...))]; print(result)。以上在交互模式下工作。
    • 好的,感谢您的澄清!你是对的 - 我误读了输出。选择它是因为它稍微优雅一些​​(对于较大的集合不需要大量递归)。感谢大家的帮助
    【解决方案2】:

    我发现的唯一方法效率很低,我很确定必须有更聪明的方法,但它确实有效。

    想法是获取所有组合,获取第一个数字的组合,遍历所有组合,从列表中删除使用的数字,生成所有组合,获取与第二个数字匹配的组合并迭代。

    这是代码。再一次,非常丑陋,但它可以完成工作:

    from collections import defaultdict
    import itertools as it
    
    def get_all_combinations(l):
        return [a for n in range(1, len(l)) for a in it.combinations(l, n)]
    
    def get_combinations_for_target(combinations, target):
        if combinations is None:
            return []
        return [combination for combination in combinations if sum(combination) == target]
    
    def get_list_without_used_numbers(l, combination):
        used_numbers = []
        for item in combination:
            used_numbers.append(item)
    
        diff_list = list(set(l) - set(used_numbers))
        return diff_list
    
    source = [1, 2, 3, 4, 5]
    combinations = get_all_combinations(source)
    combinations_first =  get_combinations_for_target(combinations, 3)
    
    combinations_both = defaultdict(dict)
    
    for combination in combinations_first:
        partial_list = get_list_without_used_numbers(source, combination)
        partial_combinations = get_all_combinations(partial_list)
        combinations_both[combination] = get_combinations_for_target(partial_combinations, 8)
    
    print(combinations_both)
    

    【讨论】:

    • 谢谢...但我从中得到的唯一输出是 "defaultdict(, {(1, 2): [(3, 5)], (3,) : [(1, 2, 5)]})" - 这是否表示库有问题?
    • 什么意思?这就是您需要的输出,这意味着组合是 (1, 2), (3, 5)(3), (1, 2, 5) 的输入 (3, 8)
    猜你喜欢
    • 2013-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多