arrays - value - print all subsets with given sum




Calculate all possibilities to get N using values from a given set (7)

Edit: Due to a misinterpretation of the question, I first answered with an efficient way to calculate the number of possibilities (instead of the possibilities themself) to get N using values from a given set. That solution can be found at the bottom of this post as a reference for other people, but first I'll give a proper answer to your questions.


Generate all possibilities, count them and give the shortest one

When generating a solution, you consider each element from the input array and ask yourself "should I use this in my solution or not?". Since we don't know the answer until after the calculation, we'll just have to try out both using it and not using it, as can be seen in the recursion step in the code below.

Now, to avoid duplicates and misses, we need to be a bit careful with the parameters for the recursive call. If we use the current element, we should also allow it to be used in the next step, because the element may be used as many times as possible. Therefore, the first parameter in this recursive call is i. However, if we decide to not use the element, we should not allow it to be used in the next step, because that would be a duplicate of the current step. Therefore, the first parameter in this recursive call is i+1.

I added an optional bound (from "branch and bound") to the algorithm, that will stop expanding the current partial solution if it is known that this solution will never be shorter then the shortest solution found so far.

package otherproblems;

import java.util.Deque;
import java.util.LinkedList;

public class GeneratePossibilities
{
    // Input
    private static int n = 50;
    // If the input array is sorted ascending, the shortest solution is
    // likely to be found somewhere at the end.
    // If the input array is sorted descending, the shortest solution is
    // likely to be found somewhere in the beginning.
    private static int[] input = {100, 80, 66, 25, 4, 2, 1};

    // Shortest possibility
    private static Deque<Integer> shortest;
    // Number of possibilities
    private static int numberOfPossibilities;

    public static void main(String[] args)
    {
        calculate(0, n, new LinkedList<Integer>());
        System.out.println("\nAbove you can see all " + numberOfPossibilities +
            " possible solutions,\nbut this one's the shortest: " + shortest);
    }

    public static void calculate(int i, int left, Deque<Integer> partialSolution)
    {
        // If there's nothing left, we reached our target
        if (left == 0)
        {
            System.out.println(partialSolution);
            if (shortest == null || partialSolution.size() < shortest.size())
                shortest = new LinkedList<Integer>(partialSolution);
            numberOfPossibilities++;
            return;
        }
        // If we overshot our target, by definition we didn't reach it
        // Note that this could also be checked before making the
        // recursive call, but IMHO this gives a cleaner recursion step.
        if (left < 0)
            return;
        // If there are no values remaining, we didn't reach our target
        if (i == input.length)
            return;

        // Uncomment the next two lines if you don't want to keep generating
        // possibilities when you know it can never be a better solution then
        // the one you have now.
//      if (shortest != null && partialSolution.size() >= shortest.size())
//          return;

        // Pick value i. Note that we are allowed to pick it again,
        // so the argument to calculate(...) is i, not i+1.
        partialSolution.addLast(input[i]);
        calculate(i, left-input[i], partialSolution);
        // Don't pick value i. Note that we are not allowed to pick it after
        // all, so the argument to calculate(...) is i+1, not i.
        partialSolution.removeLast();
        calculate(i+1, left, partialSolution);
    }

}

Calculate the number of possibilities efficiently

This is a nice example of dynamic programming. What you need to do is figure out how many possibilities there are to form the number x, using value y as the last addition and using only values smaller than or equal to y. This gives you a recursive formula that you can easily translate to a solution using dynamic programming. I'm not quite sure how to write down the mathematics here, but since you weren't interested in them anyway, here's the code to solve your question :)

import java.util.Arrays;

public class Possibilities
{
    public static void main(String[] args)
    {
        // Input
        int[] input = {100, 80, 66, 25, 4, 2, 1};
        int n = 50;

        // Prepare input
        Arrays.sort(input);

        // Allocate storage space
        long[][] m = new long[n+1][input.length];

        for (int i = 1; i <= n; i++)
            for (int j = 0; j < input.length; j++)
            {
                // input[j] cannot be the last value used to compose i
                if (i < input[j])
                    m[i][j] = 0;
                // If input[j] is the last value used to compose i,
                // it must be the only value used in the composition.
                else if (i == input[j])
                    m[i][j] = 1;
                // If input[j] is the last value used to compose i,
                // we need to know the number of possibilities in which
                // i - input[j] can be composed, which is the sum of all
                // entries in column m[i-input[j]].
                // However, to avoid counting duplicates, we only take
                // combinations that are composed of values equal or smaller
                // to input[j].
                else
                    for (int k = 0; k <= j; k++)
                        m[i][j] += m[i-input[j]][k];
            }

        // Nice output of intermediate values:
        int digits = 3;
        System.out.printf(" %"+digits+"s", "");
        for (int i = 1; i <= n; i++)
            System.out.printf(" %"+digits+"d", i);
        System.out.println();
        for (int j = 0; j < input.length; j++)
        {
            System.out.printf(" %"+digits+"d", input[j]);
            for (int i = 1; i <= n; i++)
                System.out.printf(" %"+digits+"d", m[i][j]);
            System.out.println();
        }

        // Answer:
        long answer = 0;
        for (int i = 0; i < input.length; i++)
            answer += m[n][i];
        System.out.println("\nThe number of possibilities to form "+n+
            " using the numbers "+Arrays.toString(input)+" is "+answer);
    }
}

So here is the problem:

Given input = [100 80 66 25 4 2 1], I need to find the best combination to give me 50.

Looking at this, the best would be 25+25 = 50, so I need 2 elements from the array.

Other combinations include 25+4+4+4+4+4+4+1 and 25+4+4+4+4+4+2+2+1.. etc etc

I need to find all the possibilities which gives me the sum on a value I want.

EDIT: As well as the best possibility (one with least number of terms)

Here is what I have done thus far: First build a new array (simple for loop which cycles through all elements and stores in a new temp array), check for all elements higher than my array (so for input 50, the elements 100,80,66 are higher, so discard them and then my new array is [25 4 2 1]). Then, from this, I need to check combinations.

The first thing I do is a simple if statement checking if any array elements EXACTLY match the number I want. So if I want 50, I check if 50 is in the array, if not, I need to find combinations.

My problem is, I'm not entirely sure how to find every single combination. I have been struggling trying to come up with an algorithm for a while but I always just end up getting stumped.

Any help/tips would be much appreciated.

PS - we can assume the array is always sorted in order from LARGEST to SMALLEST value.


I made a small program to help with one solution. Personally, I believe the best would be a deterministic mathematical solution, but right now I lack the caffeine to even think on how to implement it. =)

Instead, I went with a SAR approach. Stop and Reverse is a technique used on stock trading (http://daytrading.about.com/od/stou/g/SAR.htm), and is heavily used to calculate optimal curves with a minimal of inference. The Wikipedia entry for parabolical SAR goes like this:

'The Parabolic SAR is calculated almost independently for each trend in the price. When the price is in an uptrend, the SAR emerges below the price and converges upwards towards it. Similarly, on a downtrend, the SAR emerges above the price and converges downwards.'

I adapted it to your problem. I start with a random value from your series. Then the code enters a finite number of iterations.

I pick another random value from the series stack. If the new value plus the stack sum is inferior to the target, then the value is added; if superior, then decreased. I can go on for as much as I want until I satisfy the condition (stack sum = target), or abort if the cycle can't find a valid solution. If successful, I record the stack and the number of iterations. Then I redo everything.

An EXTREMELY crude code follows. Please forgive the hastiness. Oh, and It's in C#. =)

Again, It does not guarantee that you'll obtain the optimal path; it's a brute force approach. It can be refined; detect if there's a perfect match for a target hit, for example.

 public static class SAR
 {
    //I'm considering Optimal as the smallest signature (number of members).
    // Once set, all future signatures must be same or smaller.

    private static Random _seed = new Random();

    private static List<int> _domain = new List<int>() { 100, 80, 66, 24, 4, 2, 1 };

    public static void SetDomain(string domain)
    {
        _domain = domain.Split(',').ToList<string>().ConvertAll<int>(a => Convert.ToInt32(a));
        _domain.Sort();
    }

    public static void FindOptimalSAR(int value)
    {
        // I'll skip some obvious tests. For example:
        //   If there is no odd number in domain, then
        //   it's impossible to find a path to an odd
        //   value.

        //Determining a max path run. If the count goes
        //   over this, it's useless to continue.
        int _maxCycle = 10;

        //Determining a maximum number of runs.
        int _maxRun = 1000000;
        int _run = 0;

        int _domainCount = _domain.Count;

        List<int> _currentOptimalSig = new List<int>();
        List<String> _currentOptimalOps = new List<string>();
        do
        {

            List<int> currSig = new List<int>();
            List<string> currOps = new List<string>();

            int _cycle = 0;
            int _cycleTot = 0;
            bool _OptimalFound = false;

            do
            {
                int _cursor = _seed.Next(_domainCount);

                currSig.Add(_cursor);

                if (_cycleTot < value)
                {
                    currOps.Add("+");
                    _cycleTot += _domain[_cursor];
                }
                else
                {
                    // Your situation doesn't allow for negative
                    // numbers. Otherwise, just enable the two following lines.
                    // currOps.Add("-");
                    // _cycleTot -= _domain[_cursor];
                }

                if (_cycleTot == value)
                {
                    _OptimalFound = true;
                    break;
                }

                _cycle++;
            } while (_cycle < _maxCycle);

            if (_OptimalFound)
            {
                _maxCycle = _cycle;

                _currentOptimalOps = currOps;
                _currentOptimalSig = currSig;

                Console.Write("Optimal found: ");

                for (int i = 0; i < currSig.Count; i++)
                {
                    Console.Write(currOps[i]);
                    Console.Write(_domain[currSig[i]]);
                }

                Console.WriteLine(".");
            }

            _run++;

        } while (_run < _maxRun);
    }
}

And this is the caller:

        String _Domain = "100, 80, 66, 25, 4, 2, 1";

        SAR.SetDomain(_Domain);

        Console.WriteLine("SAR for Domain {" + _Domain + "}");
        do
        {
            Console.Write("Input target value: ");
            int _parm = (Convert.ToInt32(Console.ReadLine()));

            SAR.FindOptimalSAR(_parm);
            Console.WriteLine("Done.");

        } while (true);

This is my result after 100k iterations for a few targets, given a slightly modified series (I switched 25 for 24 for testing purposes):

SAR for Domain {100, 80, 66, 24, 4, 2, 1}
Input target value: 50
Optimal found: +24+24+2.
Done.
Input target value: 29
Optimal found: +4+1+24.
Done.
Input target value: 75
Optimal found: +2+2+1+66+4.
Optimal found: +4+66+4+1.
Done.

Now with your original series:

SAR for Domain {100, 80, 66, 25, 4, 2, 1}
Input target value: 50
Optimal found: +25+25.
Done.
Input target value: 75
Optimal found: +25+25+25.
Done.
Input target value: 512
Optimal found: +80+80+66+100+1+80+25+80.
Optimal found: +66+100+80+100+100+66.
Done.
Input target value: 1024
Optimal found: +100+1+80+80+100+2+100+2+2+2+25+2+100+66+25+66+100+80+25+66.
Optimal found: +4+25+100+80+100+1+80+1+100+4+2+1+100+1+100+100+100+25+100.
Optimal found: +80+80+25+1+100+66+80+80+80+100+25+66+66+4+100+4+1+66.
Optimal found: +1+100+100+100+2+66+25+100+66+100+80+4+100+80+100.
Optimal found: +66+100+100+100+100+100+100+100+66+66+25+1+100.
Optimal found: +100+66+80+66+100+66+80+66+100+100+100+100.
Done.

Cons: It is worth mentioning again: This algorithm does not guarantee that you will find the optimal values. It makes a brute-force approximation.

Pros: Fast. 100k iterations may initially seem a lot, but the algorithm starts ignoring long paths after it detects more and more optimized paths, since it lessens the maximum allowed number of cycles.


Recursion should be the easiest way to solve this (Assuming you really want to find all the solutions to the problem). The nice thing about this approach is, if you want to just find the shortest solution, you can add a check on the recursion and find just that, saving time and space :)

Assuming an element i of your array is part of the solution, you can solve the subproblem of finding the elements that sums to n-i. If we add an ordering to our solution, for example the numbers in the sum must be from the greater to the smallest, we have a way to find unique solutions.

This is a recursive solution in C#, it should be easy to translate it in java.

    public static void RecursiveSum(int n, int index, List<int> lst, List<int> solution)
    {
        for (int i = index; i < lst.Count; i++)
        {
            if (n == 0)
            {
                Console.WriteLine("");
                foreach (int j in solution)
                {
                    Console.Write(j + " ");
                }
            }
            if (n - lst[i] >= 0)
            {
                List<int> tmp = new List<int>(solution);
                tmp.Add(lst[i]);
                RecursiveSum(n - lst[i], i, lst, tmp);
            }
        }
    }

You call it with

RecursiveSum(N,0,list,new List<int>());

where N is the sum you are looking for, 0 shouldn't be changed, list is your list of allowed numbers, and the last parameter shouldn't be changed either.


The problem you pose is interesting but very complex. I'd approach this by using something like OptaPlanner(formerly Drools Planner). It's difficult to describe a full solution to this problem without spending significant time, but with optaplanner you can also get "closest fit" type answers and can have incremental "moves" that would make solving your problem more efficient. Good luck.


This is the integer knapsack problem, which is one your most common NP-complete problems out there; if you are into algorithm design/study check those out. To find the best I think you have no choice but to compute them all and keep the smallest one.

For the correct solution there is a recursive algorithm that is pretty simple to put together.

import org.apache.commons.lang.ArrayUtils;
import java.util.*;

public class Stuff {

    private final int target;
    private final int[] steps;


    public Stuff(int N, int[] steps) {
        this.target = N;
        this.steps = Arrays.copyOf(steps, steps.length);
        Arrays.sort(this.steps);
        ArrayUtils.reverse(this.steps);
        this.memoize = new HashMap<Integer, List<Integer>>(N);
    }

    public List<Integer> solve() {
        return solveForN(target);
    }

    private List<Integer> solveForN(int N) {
        if (N == 0) {
            return new ArrayList<Integer>();
        } else if (N > 0) {
            List<Integer> temp, min = null;
            for (int i = 0; i < steps.length; i++) {
                temp = solveForN(N - steps[i]);
                if (temp != null) {
                    temp.add(steps[i]);
                    if (min == null || min.size() > temp.size()) {
                        min = temp;
                    }
                }
            }
            return min;
        } else {
            return null;
        }
    }
}

It is based off the fact that to "get to N" you to have come from N - steps[0], or N - steps1, ...

Thus you start from your target total N and subtract one of the possible steps, and do it again until you are at 0 (return a List to specify that this is a valid path) or below (return null so that you cannot return an invalid path).

The complexity of this correct solution is exponential! Which is REALLY bad! Something like O(k^M) where M is the size of the steps array and k a constant.

To get a solution to this problem in less time than that you will have to use a heuristic (approximation) and you will always have a certain probability to have the wrong answer.

You can make your own implementation faster by memorizing the shortest combination seen so far for all targets (so you do not need to recompute recur(N, _, steps) if you already did). This approach is called Dynamic Programming. I will let you do that on your own (very fun stuff and really not that complicated).

Constraints of this solution : You will only find the solution if you guarantee that the input array (steps) is sorted in descending order and that you go through it in that order.

Here is a link to the general Knapsack problem if you also want to look approximation solutions: http://en.wikipedia.org/wiki/Knapsack_problem


This is the kind of problem that dynamic programming is meant to solve.

Create an array with with indices, 1 to 50. Set each entry to -1. For each element that is in your input array, set that element in the array to 0. Then, for each integer n = 2 to 50, find all possible ways to sum to n. The number of sums required is the minimum of the two addends plus 1. At the end, get the element at index 50.


You need to solve each sub-problem and store the solution. For example:

1 can only be 1. 2 can be 2 or 1+1. 4 can be 4 or 2+2 or 2+1+1 or 1+1+1+1. So you take each sub-solution and store it, so when you see 25=4+4+4+4+4+4+1, you already know that each 4 can also be represented as one of the 3 combinations.

Then you have to sort the digits and check to avoid duplicate patterns since, for example, (2+2)+(2+2)+(2+2)+(1+1+1+1)+(1+1+1+1)+(1+1+1+1) == (2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1). Six 2's and twelve 1's in both cases.

Does that make sense?





algorithm