Finding the minimum number of values in a list to sum to value

老子叫甜甜 提交于 2020-03-05 10:40:29

问题


So if I was given a sorted list/array i.e. [1,6,8,15,40], the size of the array, and the requested number..

How would you find the minimum number of values required from that list to sum to the requested number?

For example given the array [1,6,8,15,40], I requested the number 23, it would take 2 values from the list (8 and 15) to equal 23. The function would then return 2 (# of values). Furthermore, there are an unlimited number of 1s in the array (so you the function will always return a value)

Any help is appreciated


回答1:


The NP-complete subset-sum problem trivially reduces to your problem: given a set S of integers and a target value s, we construct set S' having values (n+1) xk for each xk in S and set the target equal to (n+1) s. If there's a subset of the original set S summing to s, then there will be a subset of size at most n in the new set summing to (n+1) s, and such a set cannot involve extra 1s. If there is no such subset, then the subset produced as an answer must contain at least n+1 elements since it needs enough 1s to get to a multiple of n+1.

So, the problem will not admit any polynomial-time solution without a revolution in computing. With that disclaimer out of the way, you can consider some pseudopolynomial-time solutions to the problem which work well in practice if the maximum size of the set is small.

Here's a Python algorithm that will do this:

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

This is tractable even for fairly large lists (I tested a random list of n=50 elements), provided their values are bounded. With S = [random.randint(1, 500) for _ in xrange(50)], min_subset(len(S), 8489) takes less than 10 seconds to run.




回答2:


There may be a simpler solution, but if your lists are sufficiently short, you can just try every set of values, i.e.:

  • 1 --> Not 23
  • 6 --> Not 23
  • ...
  • 1 + 6 = 7 --> Not 23
  • 1 + 8 = 9 --> Not 23
  • ...
  • 1 + 40 = 41 --> Not 23
  • 6 + 8 = 14 --> Not 23
  • ...
  • 8 + 15 = 23 --> Oh look, it's 23, and we added 2 values

If you know your list is sorted, you can skip some tests, since if 6 + 20 > 23, then there's no need to test 6 + 40.



来源:https://stackoverflow.com/questions/12611618/finding-the-minimum-number-of-values-in-a-list-to-sum-to-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!