排名和重复unranking排列排列、unranking

2023-09-11 22:46:04 作者:荒度余生

我阅读的排列我感兴趣的排名/ unranking方法。

I'm reading about permutations and I'm interested in ranking/unranking methods.

从论文的摘要:

排名功能的排列上的N个符号分配一个唯一的   在区间[0整数,n! - 1]〜上述n的!排列。相应的   unranking功能是逆:给定0到n之间的整数! - 1,   该函数的值是有这个级别的置换。

A ranking function for the permutations on n symbols assigns a unique integer in the range [0, n! - 1] to each of the n! permutations. The corresponding unranking function is the inverse: given an integer between 0 and n! - 1, the value of the function is the permutation having this rank.

我做了一个排名和unranking功能在C ++中使用next_permutation。但是,这是不实际的对于n> 8。我在找一个更快的方法和 factoradics 似乎颇为流行。 但我不知道这是否也适用于重复。那么,什么是与重复排列/ unrank排列好办法?

I made a ranking and an unranking function in C++ using next_permutation. But this isn't practical for n>8. I'm looking for a faster method and factoradics seem to be quite popular. But I'm not sure if this also works with duplicates. So what would be a good way to rank/unrank permutations with duplicates?

推荐答案

的一种方法是进行排名和unrank指数的选择由同等数目的特定组,例如

One way is to rank and unrank the choice of indices by a particular group of equal numbers, e.g.,

def choose(n, k):
    c = 1
    for f in xrange(1, k + 1):
        c = (c * (n - f + 1)) // f
    return c

def rank_choice(S):
    k = len(S)
    r = 0
    j = k - 1
    for n in S:
        for i in xrange(j, n):
            r += choose(i, j)
        j -= 1
    return r

def unrank_choice(k, r):
    S = []
    for j in xrange(k - 1, -1, -1):
        n = j
        while r >= choose(n, j):
            r -= choose(n, j)
            n += 1
        S.append(n)
    return S

def rank_perm(P):
    P = list(P)
    r = 0
    for n in xrange(max(P), -1, -1):
        S = []
        for i, p in enumerate(P):
            if p == n:
                S.append(i)
        S.reverse()
        for i in S:
            del P[i]
        r *= choose(len(P) + len(S), len(S))
        r += rank_choice(S)
    return r

def unrank_perm(M, r):
    P = []
    for n, m in enumerate(M):
        S = unrank_choice(m, r % choose(len(P) + m, m))
        r //= choose(len(P) + m, m)
        S.reverse()
        for i in S:
            P.insert(i, n)
    return tuple(P)

if __name__ == '__main__':
    for i in xrange(60):
        print rank_perm(unrank_perm([2, 3, 1], i))