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
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
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
Solution complexity:
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];
}