Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Given a target sum and a set of integers, find the closest subset of numbers that add to that target

I have a set of integers M and a target sum k. I want to find the subset of M that when added together is the closest to k without going over.

For example:

M = {1, 3, 5, 5, 14}

k = 12

answer = {1, 5, 5}

because 1 + 5 + 5 = 11 and there is no way to make 12.

I have the additional constraint that the subset can contain at most 4 elements.

In my application, the size of |M| can be large (on the order of thousands of elements). If it is not possible to find the optimal answer in a reasonable time, I am interested in solutions that at least give a "good" answer.

Right now I am solving this problem by generating 10,000 random subsets and selecting the closest one, which works better than one might expect but is slow. I'm not sure how far from optimal this actually is, but any insight on that would be interesting to me as well.

like image 990
John Shedletsky Avatar asked Oct 24 '13 16:10

John Shedletsky


People also ask

What is sum of subset problem give an example?

The SUBSET-SUM problem involves determining whether or not a subset from a list of integers can sum to a target value. For example, consider the list of nums = [1, 2, 3, 4] . If the target = 7 , there are two subsets that achieve this sum: {3, 4} and {1, 2, 4} . If target = 11 , there are no solutions.


1 Answers

Since you have a limit on the number of items that you can pick, you can do it with a reasonably straightforward algorithm.

The algorithm produces the possible sums in "generations". Each element of a generation consists of a number representing the sum, and a N-tuple of indexes in M that were used to build that sum.

Generation zero is empty; generation X+1 is produced by walking the generation X, and adding the elements of M to each value of that generation, and recording their sum for the next generation X+1.

Before computing the sum, check its N-tuple for the presence of the index of the number that you are about to add. If it's there, skip the number. Next, check the sum: if it is already present among the X+1 sums, ignore it; otherwise, record the new sum, along with the new N-tuple of indexes (append the index of the number that you added to the N-tuple from the generation X).

Here is how this would work for your inputs:

Generation 0: empty

Generation 1:

 1 - {0}
 3 - {1}
 5 - {2}
14 - {4}

Generation 2:

 4 - {0, 1}
 6 - {0, 2}
 8 - {1, 2}
10 - {2, 3}
15 - {0, 4}
17 - {1, 4}
19 - {2, 4}

Generation 3:

 9 - {0, 1, 2}
11 - {0, 2, 3}
13 - {1, 2, 3}
18 - {0, 1, 4}
20 - {0, 2, 4}
22 - {1, 2, 4}
24 - {2, 3, 4}

Generation 4:

14 - {0, 1, 2, 3}
23 - {0, 1, 2, 4}
25 - {0, 2, 3, 4}
27 - {1, 2, 3, 4}

You can now search through the four generations for a number that is closest to your target number k.

like image 122
Sergey Kalinichenko Avatar answered Nov 16 '22 02:11

Sergey Kalinichenko