分区号码N进入M分区

时间:2012-06-04 09:18:43

标签: algorithm math permutation partitioning

我正在尝试一个我必须分区否的问题。 N尽可能多地进入M分区。

示例:

N = 1 M = 3,将1分成3份

0 0 1
0 1 0
1 0 0

N = 3 M = 2,将3分成2份

2 1
1 2
3 0
0 3

N = 4 M = 4,将4分成4份

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


等等。

我编写了一个回溯算法代码。它会逐步产生所有可能的成分,但它会产生一些较大的输入。因为许多成分是相同的,只有部分的顺序不同。我想减少它。任何人都可以帮助提供更有效的方法。

我的方法:

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);
    }
}

在我的算法中。 n是N,它为每个可能的N分区填充数组部分[]。

我想知道的是,一旦生成一个合成,我想计算合成将以不同的顺序出现的次数。例如:对于N = 1,M = 3 :::合成只有一个:&lt; 0 ,0,1&GT; ,但它发生了3次。这就是我想知道的每一种可能的独特成分。

另一个例子:N = 4 M = 4

组成&lt; 0 0 0 4&gt;正在重复4次。同样,对于每一个独特的作品,我都想知道它会发生多少次。

看起来我也是通过在这里解释来得到它。思考。

感谢。

2 个答案:

答案 0 :(得分:0)

您可以将int转换为分区,如下所示:

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;
}

所以你可以按如下方式使用它:

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

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

    ... // use p

};

从这一点可以清楚地知道如何制作部件的增量版本。

答案 1 :(得分:0)

一种更简单的数学方法:

这个问题相当于在表达式f(x)中找到x ^ N的系数=(1 + x + x ^ 2 + x ^ 3 + .... + x ^ N)^ M < / p>

f(x)=((x ^(N-1)-1)/(x-1))^ M. 将其区分M次(d ^ Nf(x)/ dx ^ N),并且在x = 0时系数将是(1 / n!)*(d ^ Nf(x)/ dx ^ N);

可以使用任何数值微分技术进行分化。因此算法的复杂性是O(N * complexity_of_differentiation)..