From: jeffbg123 on
Hey,

I am trying to figure out the quickest way to do the following.

You are given a list of integers, a goal sum (integer), and an
acceptable +/- (integer).

The goal is to find a list of integers, all from the first list (all
unique) that sum up to the goal sum plus or minus the acceptable
range.

Example:

list: 1,2,3,4,5,6,7,8,9
Goal: 8
+/-: 1

It would output one of the following, whichever it found first:
1,2,4
1,3,4
1,6
1,7
........etc

Basically whatever numbers sum to 7,8, or 9

Make sense?

Is there a quick way of doing this? Notably faster than brute force?

Thanks,

-Jeff
From: gw7rib on
On 30 Jun, 18:38, jeffbg123 <jeffbg...(a)gmail.com> wrote:
> The goal is to find a list of integers, all from the first list (all
> unique) that sum up to the goal sum plus or minus the acceptable
> range.

If you have to get exactly the goal, then there is no quick general
solution - the problem is "NP hard". I'm not sure whether having an
acceptable range, instead of a single value, is going to help,
however.

Try googling for "knapsack problem", which should give you some leads.

Hope that helps.
Paul.
From: jeffbg123 on
Thanks for the advice Paul.

I am hesitant to accept solutions that are efficient for the knapsack
problem as I would suspect it would be an easier solution when all of
the values of the items are exactly the same. You do not gain anything
from adding the largest item over the smallest item. And you are not
going for the most songs, you are going to try to get the knapsack the
fullest. So I do not know if Knapsack solutions would specifically
apply to this situation.

I know that you said it should lead me in the right direction, but I
am not sure how to apply the Knapsack problem to this problem.

Thanks

-Jeff
From: Mensanator on
On Jun 30, 12:38 pm, jeffbg123 <jeffbg...(a)gmail.com> wrote:
> Hey,
>
> I am trying to figure out the quickest way to do the following.
>
> You are given a list of integers, a goal sum (integer), and an
> acceptable +/- (integer).
>
> The goal is to find a list of integers, all from the first list (all
> unique) that sum up to the goal sum plus or minus the acceptable
> range.
>
> Example:
>
> list: 1,2,3,4,5,6,7,8,9
> Goal: 8
> +/-: 1
>
> It would output one of the following, whichever it found first:
> 1,2,4
> 1,3,4
> 1,6
> 1,7
> .......etc
>
> Basically whatever numbers sum to 7,8, or 9
>
> Make sense?
>
> Is there a quick way of doing this? Notably faster than brute force?

Sure, if you use brute force intelligently:

check all combinations taken 1,2,3,...n at a time

# Python
#
# Calculate Permutations (with/without replacement)
# Combinations (with/without replacement)

def ooloop6(a, n, perm=True, repl=True):
if (not repl) and (n>len(a)): return
r0 = range(n)
r1 = r0[1:]
if perm and repl: # ok m**n
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
e = ''.join(["p = [' '.join((",v,")) ",f,"]"])
exec e
return p
if (not perm) and repl: # ok (m+n-1)!/(n!
(m-1)!)
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
i = ' and '.join(['(c%s>=c%s)' % (j,j-1) for j in r1])
e = ''.join(["p = [' '.join((",v,")) ",f," if ",i,"]"])
exec e
return p
if perm and (not repl): # ok m!/(m-n)!
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
i = ' and '.join([' and '.join(['(c%s!=c%s)' % (j,k) for k in
range(j)]) for j in r1])
e = ''.join(["p = [' '.join((",v,")) ",f," if ",i,"]"])
exec e
return p
if (not perm) and (not repl): # ok m!/(n!(m-n)!)
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
i = ' and '.join(['(c%s>c%s)' % (j,j-1) for j in r1])
e = ''.join(["p = [' '.join((",v,")) ",f," if ",i,"]"])
exec e
#print '\n\n',e,'\n\n'
return p

a = '1 2 3 4 5 6 7 8 9'.split() # list assumed to be sorted

listsumrange = range(7,10)

running_sum = 0
running_count = 0
for k in a: # combinations taken 1 at a time
s = int(k)
running_sum += s
if running_sum <= listsumrange[-1]: # don't check neddlessly
running_count += 1
if s in listsumrange:
print k

for n in xrange(2,running_count+1): # combinations taken n at a time
p = ooloop6(a,n,False,False)
pp = [[int(j) for j in i.split()] for i in p]
for k in pp:
if sum(k) in listsumrange:
print k

----------------------------------------------------------

For listsumrange = range(7,10):

7
8
9
[1, 6]
[1, 7]
[1, 8]
[2, 5]
[2, 6]
[2, 7]
[3, 4]
[3, 5]
[3, 6]
[4, 5]
[1, 2, 4]
[1, 2, 5]
[1, 2, 6]
[1, 3, 4]
[1, 3, 5]
[2, 3, 4]

Note, for 4 at a time, smallest combination [1,2,3,4]
exceeds listsumrange, so no point in checking higher combos.

For listsumrange = range(7,13):

7
8
9
[1, 6]
[1, 7]
[1, 8]
[1, 9]
[2, 5]
[2, 6]
[2, 7]
[2, 8]
[2, 9]
[3, 4]
[3, 5]
[3, 6]
[3, 7]
[3, 8]
[3, 9]
[4, 5]
[4, 6]
[4, 7]
[4, 8]
[5, 6]
[5, 7]
[1, 2, 4]
[1, 2, 5]
[1, 2, 6]
[1, 2, 7]
[1, 2, 8]
[1, 2, 9]
[1, 3, 4]
[1, 3, 5]
[1, 3, 6]
[1, 3, 7]
[1, 3, 8]
[1, 4, 5]
[1, 4, 6]
[1, 4, 7]
[1, 5, 6]
[2, 3, 4]
[2, 3, 5]
[2, 3, 6]
[2, 3, 7]
[2, 4, 5]
[2, 4, 6]
[3, 4, 5]
[1, 2, 3, 4]
[1, 2, 3, 5]
[1, 2, 3, 6]
[1, 2, 4, 5]
From: Gene on
On Jun 30, 3:20 pm, jeffbg123 <jeffbg...(a)gmail.com> wrote:
> Thanks for the advice Paul.
>
> I am hesitant to accept solutions that are efficient for the knapsack
> problem as I would suspect it would be an easier solution when all of
> the values of the items are exactly the same. You do not gain anything
> from adding the largest item over the smallest item. And you are not
> going for the most songs, you are going to try to get the knapsack the
> fullest. So I do not know if Knapsack solutions would specifically
> apply to this situation.
>
> I know that you said it should lead me in the right direction, but I
> am not sure how to apply the Knapsack problem to this problem.
>
> Thanks
>
> -Jeff

The better reference is the "subset sum" problem. There is a semi-
efficient dynamic programming solution. It's run time is polynomial,
but it depends on the magnitude of the set elements and the target.