【问题标题】:Finding the minimum number of values in a list to sum to value查找列表中值的最小数量以求和
【发布时间】:2012-09-27 07:15:53
【问题描述】:

如果给我一个排序列表/数组,即 [1,6,8,15,40],数组的大小和请求的数字..

您如何从该列表中找到所需的最小数量的值以求和所请求的数量?

例如给定数组 [1,6,8,15,40],我请求数字 23,它将从列表(8 和 15)中取 2 个值等于 23。然后该函数将返回 2 ( # 个值)。此外,数组中有无限数量的 1(因此您的函数将始终返回一个值)

感谢任何帮助

【问题讨论】:

    标签: algorithm knapsack-problem


    【解决方案1】:

    NP-complete subset-sum problem 微不足道地简化了您的问题:给定整数集合 S 和目标值 s,我们构造集合 S' 对于 S 中的每个 xk 具有值 (n+1) xk 并将目标设置为等于 (n+1) s。如果有一个原始集合的子集Ss,那么在新的集合中最多会有一个大小为n的子集到(n+1) s,这样的集合不能包含额外的1。如果没有这样的子集,则作为答案生成的子集必须至少包含 n+1 个元素,因为它需要足够的 1s 才能达到 的倍数n+1.

    因此,如果没有计算方面的革命,该问题将不允许任何多项式时间解。排除该免责声明后,您可以考虑一些 伪多项式时间 解决方案,如果集合的最大尺寸很小,这些解决方案在实践中效果很好。

    这是一个可以执行此操作的 Python 算法:

    import functools
    S = [1, 6, 8, 15, 40] # must contain only positive integers
    @functools.lru_cache(maxsize=None) # memoizing decorator
    def min_subset(k, s):
        # returns the minimum size of a subset of S[:k] summing to s, including any extra 1s needed to get there
        best = s # use all ones
        for i, j in enumerate(S[:k]):
            if j <= s:
                sz = min_subset(i, s-j)+1
                if sz < best: best = sz
        return best
    
    print min_subset(len(S), 23) # prints 2
    

    即使对于相当大的列表(我测试了 n=50 个元素的随机列表),这也是易于处理的,提供它们的值是有界的。使用S = [random.randint(1, 500) for _ in xrange(50)]min_subset(len(S), 8489) 的运行时间不到 10 秒。

    【讨论】:

      【解决方案2】:

      可能有一个更简单的解决方案,但如果您的列表足够短,您可以尝试每组值,即:

      • 1 --> 不是 23
      • 6 --> 不是 23
      • ...
      • 1 + 6 = 7 --> 不是 23
      • 1 + 8 = 9 --> 不是 23
      • ...
      • 1 + 40 = 41 --> 不是 23
      • 6 + 8 = 14 --> 不是 23
      • ...
      • 8 + 15 = 23 --> 哦,看,是 23,我们添加了 2 个值

      如果您知道您的列表已排序,则可以跳过一些测试,因为如果 6 + 20 > 23,则无需测试 6 + 40。

      【讨论】:

        猜你喜欢
        • 2015-09-29
        • 2017-09-19
        • 2015-01-16
        • 1970-01-01
        • 2016-05-22
        • 2012-04-18
        • 1970-01-01
        • 2019-03-17
        • 2021-10-07
        相关资源
        最近更新 更多