简体   繁体   中英

Partitioning a no. N into M partitions

I'm trying a problem in which I have to partition a no. N into M partitions as many as possible.

Example:

N=1 M=3 , break 1 into 3 parts

0 0 1
0 1 0
1 0 0

N=3 M=2 , break 3 into 2 parts

2 1
1 2
3 0
0 3

N=4 M=4 , break 4 into 4 parts

0 0 0 4
0 0 4 0
0 4 0 0
4 0 0 0
0 0 1 3
0 1 0 3
0 1 3 0
.
.
.

and so on.

I did code a backtrack algo. which produce all the possible compositions step by step, but it chokes for some larger input.Because many compositions are same differing only in ordering of parts.I want to reduce that.Can anybody help in providing a more efficient method.

My method:

void backt(int* part,int pos,int n) //break N into M parts
{
    if(pos==M-1)
    {
        part[pos]=n;
        ppart(part);   //print part array
        return;
    }

    if(n==0)
    {
        part[pos]=0;
        backt(part,pos+1,0);
        return;
    }

    for(int i=0;i<=n;i++)
    {
        part[pos]=i;

        backt(part,pos+1,n-i);
    }
}

In my algo. n is N and it fill the array part[] for every possible partition of N.

What I want to know is once generating a composition I want to calculate how many times that composition will occur with different ordering.For ex: for N=1 ,M=3 ::: composition is only one : <0,0,1> ,but it occurs 3 times. Thats what I want to know for every possible unique composition.

for another example: N=4 M=4

composition <0 0 0 4> is being repeated 4 times. Similarly, for every unique composition I wanna know exactly how many times it will occur .

Looks like I'm also getting it by explaining here.Thinking.

Thanks.

You can convert an int to a partitioning as follows:

vector<int> part(int i, int n, int m)
{
    int r = n; // r is num items remaining to be allocated

    vector<int> result(m, 0); // m entries inited to 0

    for (int j = 0; j < m-1; j++)
    {
        if (r == 0) // if none left stop
            break;

        int k = i % r; // mod out next bucket
        i /= r; // divide out bucket
        result[j] = k; // assign bucket
        r -= k; // remove assigned items from remaining
    }

    result[m-1] = r; // put remainder in last bucket

    return result;
}

So you can use this as follows:

for (int i = 0; true; i++)
{
    vector<int> p = part(i, 3, 4);

    if (i != 0 && p.back() == 3) // last part
       break;

    ... // use p

};

It should be clear from this how to make an incremental version of part too.

A much simpler and mathematical approach:

This problem is equivalent to finding the co-efficient of x^N in the expression f(x) = (1+x+x^2+x^3+....+x^N)^M

f(x) = ((x^(N-1) - 1)/(x-1))^M differentiate it M times(d^Nf(x)/dx^N) and the co-efficient will be (1/n!)*(d^Nf(x)/dx^N) at x = 0;

differentiation can be done using any numerical differentiation technique. So the complexity of the algorithm is O(N*complexity_of_differentiation)..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM