I'm working on a question that is asked me to compute the numbers of ways to sum to a specific value in a set of numbers
def ways_to_sum(number, set:{int}) -> int:
blah, blah
Calling
ways_to_sum(7,{2,3,5})
Would give me
2
As, first, 5+2
, and then, 2+2+3
sums to seven. The function must be recursive. I did not write the base case as I'm struggling to set it up.
This is probably not the most efficient solution but it should work, the base case of the recursion is when number = 0, the reduction step reduces number by each value in the set of numbers given (I named it values). It traces the sum using the trace dictionary, one easy way to speed it up would be to use dynamic programming and store the traces for 1,2,3,..., number in an array
def find_sum(number, values, trace = None):
if trace == None:
trace = {}
for i in values:
trace[i] = 0
if number == 0:
return [trace]
elif number < 0:
#not a sum
return None
stored_trace = []
for i in values:
trace_copy = copy.deepcopy(trace)
trace_copy[i] += 1
prev_traces = find_sum(number - i, values, trace_copy)
if prev_traces == None:
continue
for j in prev_traces:
if j not in stored_trace:
stored_trace.append(j)
return (stored_trace)
def function(number, values):
return len(find_sum(number, values))
EDIT: This should be a dynamic programming solution, which constructs the trace of the number from the traces of the number minus each element in values.
def find_sum(number, values, past_traces):
new_trace = []
for i in values:
if number - i < 0:
#this sum doesn't work
continue
if past_traces[number-i] == None:
find_sum(number - i, values, past_traces)
for j in past_traces[number - i]:
curr = copy.deepcopy(j)
curr[i] += 1
if curr not in new_trace:
new_trace.append(curr)
past_traces[number] = new_trace
return new_trace
def function(number, values):
zero_trace = {}
for i in values:
zero_trace[i] = 0
return find_sum(number, values, [[zero_trace]] + [None] * number)
I suppose this is a homework task, so instead of code I'll give you a description that should enable you to write your own code. And actually it's a lot easier to solve this problem recursively than iteratively.
We assume that the numbers in the set S
are distinct integers greater than 0. The goal is to write a function countSubsetSum(target, S)
that, given an integer target
, returns an integer that is equal to the total number of ways to sum up to target
(ignoring the order), using only multiples of numbers in S
.
We know that the answer is 0 if the set is empty or if the target is less than or equal to 0:
countSubsetSum(target, S) = 0, if target <= 0
countSubsetSum(target, S) = 0, if S is empty
Otherwise, we go through every element x
in S
, and for each element, consider two cases:
target
only using multiples of numbers in S\{x}
. Here are we are counting solutions not involving x
.target - k*x
(which may be 0 or negative, in which case we hit the base case) only using multiples of number in S\{x}
, for k = 1..Floor(target/x)
. Here we are counting solutions involving multiples of x
.We can combine both cases like this:
The number of ways to sum up to
target - k*x
only using multiples of number inS\{x}
, for allk = 0..Floor(target/x)
.
So we get:
countSubsetSum(target, S)
= Sum { countSubsetSum(target - k*x, S\{x}) | for all x in S, for all k from 0 .. Floor(target/x) }
or as pseudocode:
result := 0;
foreach (x in S)
for(k:=0; k < target/x; k++)
result := result + countSubsetSum(target - k*x, S\{x});
return result;
The time complexity of this algorithm is at least exponential. Note that we can't expect to do much better than that, since this problem is NP-complete, so assuming P<>NP, there cannot be a polynomial time algorithm.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.