6

I'm programming in java and I need to formulate an algorithm. The requirements of the algorithm are:

  • We have 3 Integer variables n, m, k;
  • We want to divide n into k parts so that the sum of the k-parts are equal to n and each part is an integer between 1 and m.
  • We want all possible combinations with the allowed integers.

For example with input set:

n = 7; m = 3; k = 4

we have two different combinations that we can formulate:

7 = 2 + 2 + 2 + 1

and

7 = 3 + 2 + 1 + 1

thank you all.

Michael Coxon
  • 5,311
  • 1
  • 24
  • 51
  • 1
    This smells like an NP-hard problem. Hopefully someone can name the problem to make your search easier – Roel Strolenberg Jun 24 '15 at 09:10
  • You want the "divisions" themselves or only their count (how much divisions exist)? – amit Jun 24 '15 at 09:11
  • 1
    I'm not sure this exactly belong with the java tag. The question here is more an algorithm problem than a java problem. The java implementation shouldn't be an issue once you have the algorithm – LBes Jun 24 '15 at 09:12
  • @RoelStrolenberg It's not NP hard. It's not even regular hard. :) – Sneftel Jun 24 '15 at 09:12
  • Seem more like a question for http://math.stackexchange.com/ – Danielson Jun 24 '15 at 09:12
  • amit, we want both the divisions and the number of them, in my example, there were 2 divisions and they were (2,2,2,1) & (3,2,1,1) – ali khorshidi rozbahani Jun 24 '15 at 09:17
  • @Sneftel Actually, if he wants to print all the possible outputs, I don't think it's even in NP. This is similar to [Bars and Stars](https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)), but in here - order does not matter, and you have an upper bound (which can be handled using generating functions) – amit Jun 24 '15 at 09:38
  • 1
    You can solve this with recursion. – xrisk Jun 24 '15 at 09:38
  • @Rishav Kundu , please get me the code of it, im not an expert in programming, thanks. – ali khorshidi rozbahani Jun 24 '15 at 09:42
  • @ali I will, let me write it myself :p – xrisk Jun 24 '15 at 09:43

3 Answers3

3

The idea is a backtraking algorithm approach (with recursion), You can decrease parameters and get partials solutions and then check if you have a right solution.

public class Problem {

    private static void algorithm(int n, int k, int m) {
        algorithmRecursive(Collections.EMPTY_LIST, n, k, m, 1);
    }

    private static void algorithmRecursive(List<Integer> partial, int n, int k, int m, int min) {
        if ( (k > 0) ) {
            // Optimization
            if ((n <= k * m) && (n >= k*min)){
                for (int i = min; i <= Math.min(m, n); i++) {
                    List<Integer> newPartial = new ArrayList<>(partial);
                    newPartial.add(i);
                    algorithmRecursive(newPartial, n - i, k - 1, m, i);
                }
            }
        } else if (n == 0) {
            // Right solution
            System.out.println(partial);
        }
    }

    public static void main(String[] args) {
        algorithm(7,4,3);
    }
}
David Pérez Cabrera
  • 4,960
  • 2
  • 23
  • 37
2

To get the count of "number of divisions" you can use Dynamic Programming, that follows the recursive formula:

D(0,0,j) = 1
D(x,0,j) = 0     x > 0
D(x,i,j) = 0     x < 0 or j<0
D(x,i,j) = D(x-j,i-1,j) + D(x,i,j-1)

The answer denoted by D(n,k,m) is the number of such divisions.
Complexity is O(n*k*m)

Java code:

public static int numDivisions(int n, int m, int k) {
    int[][][] D = new int[n+1][k+1][m];
    for (int j = 0; j < m; j++) {
        for (int x = 0; x <= n; x++) {
            D[x][0][j] = 0;
        }
        D[0][0][j] = 1;
    }
    for (int i = 1; i <= k; i++) { 
        for (int x = 0; x <= n; x++) {
            for (int j = 0; j < m; j++) {
                D[x][i][j] = 0;
                if (j > 0) D[x][i][j] += D[x][i][j-1];
                if (x-j-1 >=0) D[x][i][j] += D[x-j-1][i-1][j];
            }
        }
    }
    return D[n][k][m-1];
}

As a side note, this is similar to the stars and bars problem - but here order does not matter, and in addition you have upper bound on the number of "stars" in cell.

amit
  • 175,853
  • 27
  • 231
  • 333
1

I believe this can be done easily with recursion. First check if you can divide n at all, that is when n<=m*k && n>=k, if not, return empty array.

If it is divisible, successively choose m' from range [1..m] and choose that as first number, then get the rest recursively for parameters n'=n-'m, m'=m', k'=k-1, then return all the result.

Recursion would successfully stop only for n=0 and k=0. Time complexity should be the same as the size of output.

kajacx
  • 12,361
  • 5
  • 43
  • 70