计算有序集合中给定数字的索引

时间:2014-03-06 08:35:08

标签: algorithm combinatorics

不确定此问题是否应该在Math-Overflow上或此处,因此请先在此处尝试:

假设我们得到一个N 1和M 0的数字。

有(M + N)!/(M!* N!)不同的这样的数字,可以在可数集中排序。

例如,具有2个1和3个零的所有数字的有序集合是:

  • 0 00011
  • 1 00101
  • 2 00110
  • 3 01001
  • 4 01010
  • 5 01100
  • 6 10001
  • 7 10010
  • 8 10100
  • 9 11000

我们如何有效地计算相应集合中给定数字的索引?

注意:此问题的输入数字,整个(相应)设置。

3 个答案:

答案 0 :(得分:6)

choose (n, k) = n! / k! / (n-k)!

观察排序集的以下结构:

0 0|0011 1 0|0101 2 0|0110 3 0|1001 4 0|1010 5 0|1100 ------ 6 1|0001 7 1|0010 8 1|0100 9 1|1000

在排序集中,总共有choose (N + M, M)个数字(长度为N + M的二进制字符串)。 首先将数字从零开始,其中有choose (N + M-1, M-1)个。然后输入一个开头的数字,其中有choose (N-1 + M, M)个。这两个部分中的每一部分也都有分类。

所以,如果您的数字b 1 b 2 ... b k 以零开头(b 1 = 0),其有序集合中的索引与所有二进制字符串{{的有序集合中的b 2 ... b k 的索引相同1}}个和N个零。如果它以1开头(b 1 = 1),则其在有序集合中的索引与b 2 的索引相同... b k < / sub>在M-1个和N-1个零的所有二进制字符串的有序集合中,加上以零开头的二进制字符串的总数,即{{1 }}

通过这种方式,您递归地下降到涉及原始二进制字符串后缀的子问题,每当遇到1时,将所需数量增加一些。最后,您得到一个空二进制字符串,显然是一个,只包含0个零和0个的字符串。

答案 1 :(得分:5)

这在组合算法中称为排名。这是一个C函数,可以帮助您:

unsigned long rank_choose(unsigned long n, unsigned long k, unsigned long c) {
  unsigned long res = 0;
  for (; n > 0; n--) {
    if (c & 1) { res += binomial(n-1, k); k--;}
    c >>= 1;
  }
  return res;
}

假设您有一个函数binomial(n, k)来计算系数n!/k!/(n-k)!。请注意,我在此提出的解决方案使用 endianess reverse 表示:

const int m = 5, n = 2;
int k = 12;
std::cout << std::bitset<m>(k) << " " << rank_choose(m, n, k) << std::endl;
k = 9;
std::cout << std::bitset<m>(k) << " " << rank_choose(m, n, k) << std::endl;

返回:

01100 2
01001 7

以下是另一个字节的解决方案:

unsigned long rank_choose_rev(unsigned long n, unsigned long k, unsigned long c) {
  unsigned long res = 0, mask = 1<<(n-1);
  for (; n > 0; n--) {
    if (c & mask) { res += binomial(n-1, k); k--;}
    mask >>= 1;
  }
  return res;
}

然后

01100 5
01001 3

注意:下面的@Gassa很好地描述了这些算法(给他+1)。

答案 2 :(得分:0)

我将在一个例子的帮助下解释一个解决方案。假设有3 ones3 zeroes,我们必须找到010110的索引

左起第一个位于第二个位置。因此,所有在其右边都有双零的数字应小于这个数字:

00---- (C(4,3)) = 4

现在将此位置放在其位置并移至下一个位置。下一个是在第4位。因此,以下所有数字应小于候选人:

0100-- (C(2,2)) = 1

现在将此位置放在其位置并移至下一个位置。下一个是在第5位。因此,以下所有数字应小于候选人:

01010- (C(1,1)) = 1

Hence the number of numbers less than the candidate = 4 + 1 + 1 = 6

000111
001011
001101
001110
010011
010101
010110