查找整数分区的字典顺序

Dan*_*iel 8 c algorithm lexicographic integer-partition

对于排列,给定Nk,我有一个函数,找到按字典顺序k排列的N排列.另外,给定一个排列perm,我有一个函数,可以在所有排列中找到排列的词典索引N.为此,我使用了本答案中建议的"因子分解" .

现在我想对整数分区做同样的事情N.例如,因为N=7,我希望能够在索引(左)和分区(右)之间来回:

 0 ( 7 )
 1 ( 6 1 )
 2 ( 5 2 )
 3 ( 5 1 1 )
 4 ( 4 3 )
 5 ( 4 2 1 )
 6 ( 4 1 1 1 )
 7 ( 3 3 1 )
 8 ( 3 2 2 )
 9 ( 3 2 1 1 )
10 ( 3 1 1 1 1 )
11 ( 2 2 2 1 )
12 ( 2 2 1 1 1 )
13 ( 2 1 1 1 1 1 )
14 ( 1 1 1 1 1 1 1 )
Run Code Online (Sandbox Code Playgroud)

我尝试了一些事情.我想出的最好的是

sum = 0;
for (int i=0; i<length; ++i)
  sum += part[i]*i;
return sum;
Run Code Online (Sandbox Code Playgroud)

它给出了以下内容:

 0  0( 7 )
 1  1( 6 1 )
 2  2( 5 2 )
 3  3( 5 1 1 )
 3  4( 4 3 )
 4  5( 4 2 1 )
 6  6( 4 1 1 1 )
 5  7( 3 3 1 )
 6  8( 3 2 2 )
 7  9( 3 2 1 1 )
10 10( 3 1 1 1 1 )
 9 11( 2 2 2 1 )
11 12( 2 2 1 1 1 )
15 13( 2 1 1 1 1 1 )
21 14( 1 1 1 1 1 1 1 )
Run Code Online (Sandbox Code Playgroud)

这不太有效,但似乎正在走上正轨.我想出了这个,因为它计算了我有多少次移动一个数字(比如6,3,26,3,1,1).但是,我看不出如何修复它,因为我不知道如何解决事情必须重新组合的问题(比如6,3,1,16,2,2).

Pen*_*One 3

想想为什么“阶乘分解”适用于排列,同样的逻辑在这里也适用。但是,您必须使用分区函数来计算最多 的最大部分的分区数,而不是使用对象k!的排列数。对于,这些数字是:kp(n,k)nkn=7

k | p(7,k)
0 | 0
1 | 1
2 | 4
3 | 8
4 | 11
5 | 13
6 | 14
7 | 15
Run Code Online (Sandbox Code Playgroud)

(3,2,1,1)例如,要获取 的词典索引,您可以计算

p(3+2+1+1) - [ p(3+2+1+1,3-1) + p(2+1+1,2-1) + p(1+1,1-1) + p(1,1-1) ] - 1
Run Code Online (Sandbox Code Playgroud)

这是15 - [4 + 1 + 0 + 0] - 1 = 9. 在这里,您计算的是最大部分小于 3 的 7 的分区数加上最大部分小于 2 的 4 的分区数加上...相同的逻辑可以逆转这一点。在 C 中,(未经测试!)函数是:

int
rank(int part[], int size, int length) {
    int r = 0;
    int n = size;
    int k;
    for (int i=0; i<length; ++i) {
        k = part[i];
        r += numPar(n,k-1);
        n -= k;        
    }
    return numPar(size)-r;
}

int
unrank (int n, int size, int part[]) {
    int N = size;
    n = numPar(N)-n-1;

    int length = 0;

    int k,p;
    while (N>0) {
        for (k=0; k<N; ++k) {
            p = numPar(N,k);
            if (p>n) break;
        }
        parts[length++] = k;
        N -= k;
        n -= numPar(N,k-1);
    }
    return length;
}
Run Code Online (Sandbox Code Playgroud)

这里numPar(int n)应该返回 的分区数n,并且最多numPar(int n, int k)应该返回 的最大部分的分区数。您可以使用递归关系自己编写这些内容。nk