/README.md
Markdown | 66 lines | 48 code | 18 blank | 0 comment | 0 complexity | 5d29ff9499bd54708238c899d4411c1b MD5 | raw file
- SubSetSum Algorithm
- -------------------
- _Delphi implementation_
- This is a polynomial algorithm to solve the SubSetSum problem (which is non-polynomial). The limitation is that it works for _positive numbers only_. The implementation is based on the [Wikipedia algorithm](http://en.wikipedia.org/wiki/Subset_sum_problem#Polynomial_time_approximate_algorithm).
- The algorithm is considered polynomial thanks to the trimming step. The main iteration can be devided in 2 steps:
- 0. New combinations are appended, increasing the size of the list
- 0. Every sum that exceeds the goal sum is discarded permanently
- In other words, the list keeps growing and shrinking, and that mantains the size of the list more or less the same. That is the reason it works for positive numbers only. Once the sum of a combination exceeds the goal, it is discarded. That could never be done if there were a possibility of decreasing the value (negative numbers).
- This algorithm was used to solve a financial problem in the project I was working. The software was 100% client-server database driven, so the data comes from a DataSet.
- *Notes:*
- 0. The wikipedia algorithm returns only a boolean. This implementation returns a string where:
- a) Each line is a possible combination
- b) Items in the line are separated by comma
- Ex: Return = 2 possible combinations:
- - 1st and 2nd item
- - 1st and 3rd item
-
- In this case, the return of the function would be the string:
- 1,2
- 1,3
- 0. This algorithm was written in Delphi 7 build 4453, no updates (unfortunately, but I had no choice on that). It looks like there is a bug in this version and I couldn't use the Double data type.
- (I had a case with two variables storing the same value: 7.2. The test: if Var1 = Var2 then... was returning False!!)
- I switched the data types to Currency as a work arround.
- 0. The original trimming step, excludes values that are greater than goal sum and also similar values (for instance: if item1 + item2 + item3 = 500 and item4 + item5 = 500, it just keeps one of them). That works only because the original result is a Boolean. This implementation returns a list with all possible combinations, so it must keep similar values. In this case, there's no point in sorting the list (won't search for similar values), the QuickSort function is commented out.
- 0. Note the difference between upper "S" (list with sums) and lower "s" (goal sum)
- Text from wikipedia:
- An approximate version of the subset sum would be: given a set of N numbers x1, x2, ..., xN and a number s, output
- - yes, if there is a subset that sums up to s;
- - no, if there is no subset summing up to a number between (1 - c)s and s for some small c > 0;
- - any answer, if there is a subset summing up to a number between (1 - c)s and s but no subset summing up to s.
- If all numbers are non-negative, the approximate subset sum is solvable in time polynomial in N and 1/c.
- The solution for subset sum also provides the solution for the original subset sum problem in the case where the numbers are small (again, for nonnegative numbers).
- If any sum of the numbers can be specified with at most P bits, then solving the problem approximately with c = 2-P is equivalent to solving it exactly.
- Then, the polynomial time algorithm for approximate subset sum becomes an exact algorithm with running time polynomial in N and 2P (i.e., exponential in P).
- The algorithm for the approximate subset sum problem is as follows:
- initialize a list S to contain one element 0.
- for each i from 1 to N do
- let T be a list consisting of xi + y, for all y in S
- let U be the union of T and S
- sort U
- make S empty
- let y be the smallest element of U
- add y to S
- for each element z of U in increasing order do
- //trim the list by eliminating numbers close to one another
- //and throw out elements greater than s
- if y + cs/N < z = s, set y = z and add z to S
- if S contains a number between (1 - c)s and s, output yes, otherwise no
- _PS: sorry for the poor english_ :)