Find all combinations of a given set of integers summing up to a given sum

≯℡__Kan透↙ 提交于 2019-12-06 15:36:28

问题


I am looking for an answer to the following problem.

Given a set of integers (no duplicates) and a sum, find all possible combinations of the set's elements summing up to the sum. Solutions order does not matter (solutions {2, 2, 3} and {3, 2 ,2} are equal).

Please note that the final combination does not need to be a set, as it can contain duplicates.

Example: Set {2,3,5} Sum 10

Result: {2, 2, 2, 2, 2}, {2, 2, 3, 3}, {2, 3, 5}, {5, 5}

I've looked at Subset Sum problem as well as Coin Change problem, but couldn't adapt them to suit my needs. I am not really familiar with dynamic programming, so it's probably doable, however I couldn't figure it out.

As I am dealing with a fairly large set of elements (around 50), precomputing all the sets is not an option as it would take a very long time. A way to pull out different solutions from a Subset Sum table would be preferable (if possible).

Any advice, tips, or sample code would be appreciated!


回答1:


This is known as the Change-making problem and is a classic example in dynamic programming.

Some earlier answers have calculated the total count of solutions, whilst the question has asked for an enumeration of the possible solutions.

You haven't tagged your question with a language, so here's an implementation in Python. Adapt it to whatever language you please by using your language's "bag" datatype (n.b. the Counter is Python's "bag").

from collections import Counter

def ways(total, coins):
    ways = [[Counter()]] + [[] for _ in range(total)]
    for coin in coins:
        for i in range(coin, total + 1):
            ways[i] += [way + Counter({coin: 1}) for way in ways[i-coin]]
    return ways[total]

The output datatype is a list of bags. Demo usage for printing them:

>>> from __future__ import print_function  # for Python 2 compatibility
>>> for way in ways(total=10, coins=(2,3,5)):
...     coins = (coin for coin,count in way.items() for _ in range(count))
...     print(*coins)
... 
2 2 2 2 2
2 2 3 3
2 3 5
5 5



回答2:


Here is a Haskell function that calculates the answer:

partitions 0 xs = [[]]
partitions _ [] = []
partitions n (xxs@(x:xs)) | n < 0 = []
                          | otherwise = (map (x:) (partitions (n-x) xxs)) ++ partitions n xs

Examples:

*Main>  partitions 1 [1]
[[1]]
*Main>  partitions 5 [1..5]
[[1,1,1,1,1],[1,1,1,2],[1,1,3],[1,2,2],[1,4],[2,3],[5]]
*Main> length $ partitions 10 [1..10]
42
*Main> length $ partitions 20 [1..20]
627
*Main> length $ partitions 40 [1..40]
37338
*Main> partitions 10 [1,2,4]
[[1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,2],[1,1,1,1,1,1,2,2],[1,1,1,1,1,1,4],[1,1,1,1,2,2,2],[1,1,1,1,2,4],[1,1,2,2,2,2],[1,1,2,2,4],[1,1,4,4],[2,2,2,2,2],[2,2,2,4],[2,4,4]]

Semi-live demo




回答3:


Solution complexity:

  • time: O(n*M)
  • memory: O(M),

where M is value of sum, n is set size

int numberOfSums(Set<Integer> values, int sum) {
    // sumCount[i] -> number of ways to get sum == i 
    int sumCount[] = new int[sum+1];
    sumCount[0] = 1;
    for(int v : values) {
        for(int i=0; i<=sum-v; ++i)
            sumCount[i+v] += sumCount[i];
    }
    return sumCount[sum];
}


来源:https://stackoverflow.com/questions/41806819/find-all-combinations-of-a-given-set-of-integers-summing-up-to-a-given-sum

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