given an array of elements (all elements are unique ) , given a sum
s find all the subsets having sum s.
for ex array {5,9,1,3,4,2,6,7,11,10}
sum is开发者_StackOverflow 10
possible subsets are {10}, {6,4}, {7,3}, {5,3,2}, {6,3,1}
etc.
there can be many more.
also find the total number of these subsets.
please help me to solve this problem..
It is a famous backtracking problem which can be solved by recursion. Basically its a brute force approach in which every possible combination is tried but 3 boundary conditions given at least prune the search.
Here is algorithm:
s variable for the sum of elements selected till now.
r variable for the overall sum of the remaining array.
M is the sum required.
k is index starting with 0
w is array of given integers
Sum(k,s,r)
{
x[k]:=1; //select the current element
if(s<=M & r>=M-s & w[k]<=M-s)
then
{
if(s+w[k]==M)
then output all i [1..k] that x[i]=1
else
sum(k+1,s+w[k],r-w[k])
}
x[k]:=0 //don't select the current element
if(s<=M) & (r>=M-s) & (w[k]<=M-s)
then
{
if (M==s)
then output all i [1..k] that x[i]=1
else
sum(k+1,s,r-w[k])
}
}
I am using an array "x" to mark the candidate numbers selected for solution. At each step 3 boundary conditions are checked:
1. Sum of selected elements in "x" from "w" shouldn't exceed M. s<M.
2. Remaining numbers in array should be able to complete M. r>=M-s.
3. Single remaining value in w shouldn't overflow M. w[k]<=M-s.
If any of the condition is failed, that branch is terminated.
Here's some python code doing what you want. It makes extensive use of itertools so to understand it you might want to have a look at the itertools docs.
>>> import itertools
>>> vals = (5,9,1,3,4,2,6,7,11,10)
>>> combos = itertools.chain(*((x for x in itertools.combinations(vals, i) if sum(x) == 10) for i in xrange(len(vals)+1)))
>>> for c in combos: print c
...
(10,)
(9, 1)
(3, 7)
(4, 6)
(5, 1, 4)
(5, 3, 2)
(1, 3, 6)
(1, 2, 7)
(1, 3, 4, 2)
What it does is basically this:
- For all possible subset sizes -
for i in xrange(len(vals)+1)
, do: - Iterate over all subsets with this size -
for x in itertools.combinations(vals, i)
- Test if the sum of the subset's values is 10 -
if sum(x) == 10
- In this case yield the subset
For each subset size another generator is yielded, so I'm using itertools.chain
to chain them together so there's a single generator yielding all solutions.
Since you have only a generator and not a list, you need to count the elements while iterating over it - or you could use list(combos)
to put all values from the generator into a list (this consumes the generator, so don't try iterating over it before/after that).
Since you don't say if it's homework or not, I give only some hints:
let
nums
be the array of numbers that you can use (in your examplenums = {5,9,1,3,4,2,6,7,11,10}
)let
targetSum
be the sum value you're given (in your exampletargetSum = 10
)sort
nums
: you don't want to search for solutions using elements ofnums
that are bigger of yourtargetSum
let
S_s
be a set of integers taken fromnums
whose sum is equal tos
let
R_s
be the set of allS_s
you want to find
R_s
(in your exampleR_10
)now, assume that you have a function
find(i, s)
which returnsR_s
using the the sub-array ofnums
starting from positioni
if
nums[i] > s
you can stop (remember that you have previously sortednums
)if
nums[i] == s
you have foundR_s = { { nums[i] } }
, so return itfor every
j in [1 .. nums.length - 1]
you want to computeR_s' = find(i + j, targetSum - nums[i])
, then addnums[i]
to every set inR_s'
, and add them to your resultR_s
solve your problem by implementing
find
, and callingfind(0, 10)
I hope this helps
精彩评论