4

A partition of an integer n is a way of writing n as a sum of positive integers. For

example, for n=7, a partition is 1+1+5. I need a program that finds all the

partitions of an integer 'n' using 'r' integers. For example, all the partitions of n=7

using r=3 integers are 1+1+5, 1+2+4, 1+3+3, 2+2+3.

This is what I have so far:

#include <iostream>
#include <vector>

using namespace std;

void print (vector<int>& v, int level){
    for(int i=0;i<=level;i++)
        cout << v[i] << " ";
    cout << endl;
}

void part(int n, vector<int>& v, int level){
    int first; /* first is before last */

    if(n<1) return ;
    v[level]=n;
    print(v, level);

    first=(level==0) ? 1 : v[level-1];

    for(int i=first;i<=n/2;i++){
        v[level]=i; /* replace last */
        part(n-i, v, level+1);
    }
}

int main(){
    int num;
    cout << "Enter a number:";
    cin >> num;

    vector<int> v(num);

    part(num, v, 0);
}

The output of this program is:

Enter a number:5
5
1 4
1 1 3
1 1 1 2
1 1 1 1 1
1 2 2
2 3

Process returned 0 (0x0)   execution time : 1.837 s
Press any key to continue.

How can I change my code so I can have that 'r' variable?

EDIT:

In case it was not clear, the 'r' value represents the number of integers per partition. So in the case above, if r=2, then the partitions can only have two integers in them. The partitions would be 4+1, and 3+2. The 'r' value should be entered by the user.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
user3519448
  • 111
  • 1
  • 9

4 Answers4

1

Essentially what Codor said, plus you don't need to recurse further into part() once you found a partition of the target length since they would be longer:

#include <iostream>
#include <vector>

using namespace std;

void print (vector<int>& v, int level){
    for(int i=0;i<=level;i++)
        cout << v[i] << " ";
    cout << endl;
}

void part(int n, vector<int>& v, int level, int r){
    int first; /* first is before last */

    if(n<1) return ;
    v[level]=n;
    if( level+1 == r ) {
        print(v, level);
        return;
    }

    first=(level==0) ? 1 : v[level-1];

    for(int i=first;i<=n/2;i++){
        v[level]=i; /* replace last */
        part(n-i, v, level+1, r);
    }
}

int main(){
    int num,r;
    cout << "Enter a number:";
    cin >> num;
    cout << "Enter size (r):";
    cin >> r;

    vector<int> v(num);

    part(num, v, 0, r);
}

Output:

Enter a number:5
Enter size (r):2
1 4
2 3
TripeHound
  • 2,721
  • 23
  • 37
1

The function listed below does what you require - it efficiently enumerates all partitions of an integer myInt, which sizes are PartitionSize and whose parts are always >=MinVal and <=MaxVal.

This function uses a std::vector to store each partition, but a fixed size array can be substituted in lieu of that vector in order to facilitate straightforward porting to plain C.

This is not a recursive function! That's why its code is much longer and complex, but as a bonus it is faster for long partitions and is using less RAM for the stack and the parts/elements of each partition are listed in an ascending order (left-to-right) and the partitions themselves are ordered lexicographically (top-to-bottom).

void GenPartitions(const unsigned int myInt,
                   const unsigned int PartitionSize,
                   unsigned int MinVal,
                   unsigned int MaxVal)
{
    if ((MaxVal = MaxPartitionVal(myInt, PartitionSize, MinVal, MaxVal)) == 0)
        return;

    if ((MinVal = MinPartitionVal(myInt, PartitionSize, MinVal, MaxVal)) == unsigned int(-1))
        return;

    std::vector<unsigned int> partition(PartitionSize);
    unsigned int idx_Last = PartitionSize - 1;
    unsigned int idx_Dec = idx_Last;    //The point that needs to be decremented
    unsigned int idx_Spill = 0;         //Index where the remainder starts spilling leftwise
    unsigned int idx_SpillPrev;         //Copy of the old idx_Spill for optimization of the last "while loop".

    unsigned int LeftRemain = myInt - MaxVal - (idx_Dec - 1)*MinVal;    //The remaining value that needs to be spilled leftwise
    partition[idx_Dec] = MaxVal + 1;    //Initialize first partition. It will be decremented as soon as it enters the "do" loop.

    //std::cout << std::setw(idx_Dec * 3 + 1) << "" << "v" << std::endl;    //Show the first Decrement Point

    do {
        unsigned int val_Dec = partition[idx_Dec] - 1;      //Value AFTER decrementing
        partition[idx_Dec] = val_Dec;                       //Decrement at the Decrement Point

        idx_SpillPrev = idx_Spill;          //For optimization so the last "while loop" does not do unnecessary work.
        idx_Spill = idx_Dec - 1;            //Index where the remainder starts getting spilled. Before the Decrement Pint (not inclusive)

        while (LeftRemain > val_Dec)        //Spill the remainder leftwise while limiting its magnitude, in order to satisfy the left-to-right ascending ordering.
        {
            partition[idx_Spill--] = val_Dec;
            LeftRemain -= val_Dec - MinVal; // Adjust remainder by the amount used up (minVal is assumed to be there already)
            //std::cout << std::setw(((idx_Spill + 1) * 3) + 1) << "" << "-" << std::endl;  //Show the remainder spillage
        }   //For platforms without hardware multiplication, it is possible to calculate the expression (idx_Dec - idx_Spill)*val_Dec inside this loop by multiple additions of val_Dec.

        partition[idx_Spill] = LeftRemain;  //Spill last remainder of remainder
        //std::cout << std::setw((idx_Spill * 3) + 1) << "" << "*" << std::endl;    //Show the last remainder of remainder

        char a = (idx_Spill) ? ~((-3 >> (LeftRemain - MinVal)) << 2) : 11;  //when (LeftRemain == MinVal) then it computes to 11
        char b = (-3 >> (val_Dec - LeftRemain));

        switch (a & b)  //Switch depending on relative magnitudes of elements before and after the partition[idx]. Cases 0, 4, 8 can never occur.
        {
            case 1:
            case 2:
            case 3: idx_Dec = idx_Spill;
                    LeftRemain = 1 + (idx_Spill - idx_Dec + 1)*MinVal; 
                    break;

            case 5: for (++idx_Dec, LeftRemain = (idx_Dec - idx_Spill)*val_Dec; (idx_Dec <= idx_Last) && (partition[idx_Dec] <= MinVal); idx_Dec++) //Find the next value, that can be decremented while satisfying the left-to-right ascending ordering.
                        LeftRemain += partition[idx_Dec];

                    LeftRemain += 1 + (idx_Spill - idx_Dec + 1)*MinVal;
                    break;

            case 6:
            case 7:
            case 11:idx_Dec = idx_Spill + 1;
                    LeftRemain += 1 + (idx_Spill - idx_Dec + 1)*MinVal;
                    break;


            case 9: for (++idx_Dec, LeftRemain = idx_Dec * val_Dec; (idx_Dec <= idx_Last) && (partition[idx_Dec] <= (val_Dec + 1)); idx_Dec++)  //Find the next value, that can be decremented while satisfying the left-to-right ascending ordering.
                        LeftRemain += partition[idx_Dec];

                    LeftRemain += 1 - (idx_Dec - 1)*MinVal;
                    break;

            case 10:for (LeftRemain += idx_Spill * MinVal + (idx_Dec - idx_Spill)*val_Dec + 1, ++idx_Dec; (idx_Dec <= idx_Last) && (partition[idx_Dec] <= (val_Dec - 1)); idx_Dec++)    //Find the next value, that can be decremented while satisfying the left-to-right ascending ordering. Here [idx_Dec] == [cur]+1. 
                        LeftRemain += partition[idx_Dec];

                    LeftRemain -= (idx_Dec - 1)*MinVal;
                    break;
        }

        while (idx_Spill > idx_SpillPrev)   //Set the elements where the spillage of the remainder did not reach.  For optimization, going down only to idx_SpillPrev 
            partition[--idx_Spill] = MinVal;    //For platforms without hardware multiplication, it is possible to calculate the expression idx_Spill*MinVal inside this loop by multiple additions of MinVal, followed by another "while loop" iterating from idx_SpillPrev to zero (because the optimization skips these iterations). If, so, then both loops would need to be moved before the "switch statement"

        DispPartition(partition);   //Display the partition ...or do sth else with it           
        //std::cout << std::setw((idx_Dec * 3) + 1) << "" << "v" << std::endl;  //Show the Decrement Points

    } while (idx_Dec <= idx_Last);
}

Below is a sample output of this function:

SAMPLE OUTPUT OF: GenPartitions(20, 4, 1,10):
1, 1, 8,10
1, 2, 7,10
1, 3, 6,10
2, 2, 6,10
1, 4, 5,10
2, 3, 5,10
2, 4, 4,10
3, 3, 4,10
1, 1, 9, 9
1, 2, 8, 9
1, 3, 7, 9
2, 2, 7, 9
1, 4, 6, 9
2, 3, 6, 9
1, 5, 5, 9
2, 4, 5, 9
3, 3, 5, 9
3, 4, 4, 9
1, 3, 8, 8
2, 2, 8, 8
1, 4, 7, 8
2, 3, 7, 8
1, 5, 6, 8
2, 4, 6, 8
3, 3, 6, 8
2, 5, 5, 8
3, 4, 5, 8
4, 4, 4, 8
1, 5, 7, 7
2, 4, 7, 7
3, 3, 7, 7
1, 6, 6, 7
2, 5, 6, 7
3, 4, 6, 7
3, 5, 5, 7
4, 4, 5, 7
2, 6, 6, 6
3, 5, 6, 6
4, 4, 6, 6
4, 5, 5, 6
5, 5, 5, 5

If you want to compile it, the helper functions are below:

#include <iostream>
#include <iomanip>
#include <vector> 

unsigned int MaxPartitionVal(const unsigned int myInt,
                             const unsigned int PartitionSize,
                             unsigned int MinVal,
                             unsigned int MaxVal)
{
    if ((myInt < 2)
        || (PartitionSize < 2)
        || (PartitionSize > myInt)
        || (MaxVal < 1)
        || (MinVal > MaxVal)
        || (PartitionSize > myInt)
        || ((PartitionSize*MaxVal) < myInt )
        || ((PartitionSize*MinVal) > myInt))    //Sanity checks
        return 0;

    unsigned int last = PartitionSize - 1;

    if (MaxVal + last*MinVal > myInt)
        MaxVal = myInt - last*MinVal;   //It is not always possible to start with the Maximum Value. Decrease it to sth possible

    return MaxVal;
}

unsigned int MinPartitionVal(const unsigned int myInt,
                             const unsigned int PartitionSize,
                             unsigned int MinVal,
                             unsigned int MaxVal)
{
    if ((MaxVal = MaxPartitionVal(myInt, PartitionSize, MinVal, MaxVal)) == 0)   //Assume that MaxVal has precedence over MinVal
        return unsigned int(-1);

    unsigned int last = PartitionSize - 1;

    if (MaxVal + last*MinVal > myInt)
        MinVal = myInt - MaxVal - last*MinVal;  //It is not always possible to start with the Minimum Value. Increase it to sth possible

    return MinVal;
}

void DispPartition(const std::vector<unsigned int>& partition)
{
    for (unsigned int i = 0; i < partition.size()-1; i++)       //DISPLAY THE PARTITON HERE ...or do sth else with it.
            std::cout << std::setw(2) << partition[i] << ",";

    std::cout << std::setw(2) << partition[partition.size()-1] << std::endl;
}

P.S.
I was motivated to create this non-recursive function for a microcontroller that had very few bytes of free RAM left for the stack (it had a lot of program memory, though).

George Robinson
  • 1,500
  • 9
  • 21
0

A sort of "hack" would be to make r an argument of part, pass it along recursively an just print the output if level equals r.

Codor
  • 17,447
  • 9
  • 29
  • 56
0

How about this? Have an additional argument passed as reference for r, and increment r each time within the recursion block?

#include <iostream>
#include <vector>

using namespace std;

void print (vector<int>& v, int level){
    for(int i=0;i<=level;i++)
        cout << v[i] << " ";
    cout << endl;
}

void part(int n, vector<int>& v, int level, int &r){
    int first; /* first is before last */

    if(n<1) return ;
    v[level]=n;
    print(v, level);

    first=(level==0) ? 1 : v[level-1];

    for(int i=first;i<=n/2;i++){
        v[level]=i; /* replace last */
        r++;
        part(n-i, v, level+1, r);
    }
}

int main(){
    int num;
    cout << "Enter a number:";
    cin >> num;

    int r = 0;
    vector<int> v(num);

    part(num, v, 0, r);
    cout << "r = " << r << endl;
}

Output comes as:

Enter a number:5 
1 4 
1 1 3 
1 1 1 2 
1 1 1 1 1 
1 2 2 
2 3 
r = 6

Is this what you are looking for?

Dr. Debasish Jana
  • 6,980
  • 4
  • 30
  • 69
  • Not quiet. The user needs to enter the 'r' value. For example, the 'n' value is 14 (which is entered by the user as shown in the code). Then the user enters a 'r' value. The 'r' value represents the number of integers in each partition. If the 'r' value is 3, then there can only be three integers per partition. So 6+6+2. 10+2+2, 12+1+1, 5+5+4, etc. – user3519448 Apr 10 '14 at 13:17