根据位置计算组合

时间:2011-05-10 19:37:27

标签: c++ combinations combinatorics

我有这样的组合:

1,2,3,4 //索引0
1,2,3,5 //索引1
1,2,3,6 //索引2

依此类推,直到7,8,9,10

所以这将是组合学中的n = 10 k = 4

如何按指数计算组合

例如当我的索引== 1
时 myCmb = func(index)
返回1,2,3,5

这是一个例子,我需要这个最大数字,更多参数和没有(如果可能的话)许多循环

我找到这样的东西来获得位置: http://answers.yahoo.com/question/index?qid=20110320070039AA045ib

我现在要反过来......

我用C ++编程 感谢任何sugesstions或帮助

2 个答案:

答案 0 :(得分:1)

好像你想要find the k-combination for a given number

example之后,这里应该有用:

#include <cstddef>
#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
#include <boost/math/special_functions/binomial.hpp>


std::size_t Choose(double n, double k) {
  using boost::math::binomial_coefficient;
  if (n < k) return 0;
  return static_cast<std::size_t>(binomial_coefficient<double>(n, k));
}

// Returns the largest n such that Choose(n, k) <= pos.
int CombinationElement(int k, int pos) {
  int n = k;
  int coeff = 1, prev_coeff = 0;

  while (coeff <= pos) {
    coeff = Choose(++n, k);
    prev_coeff = coeff;
  }

  return n - 1;
}

// Returns an k-combination at position pos.
std::vector<int> Combination(int k, int pos) {
  std::vector<int> combination;
  for (; k > 0; --k) {
    int n = CombinationElement(k, pos);
    combination.push_back(n);
    pos -= Choose(n, k);
  }
  return combination;
}

int main(int argc, char** argv) {
  using std::cout;
  using std::endl;

  if (argc != 3) {
    cout << "Usage:  $ " << argv[0] << " K POS" << endl;
    cout << "Prints the K-combination at position POS." << endl;
    return 1;
  }

  int k = boost::lexical_cast<int>(argv[1]);
  int pos = boost::lexical_cast<int>(argv[2]);

  std::vector<int> combination = Combination(k, pos);

  for (int i = 0; i < k; i++)
    cout << combination[i] << " ";
  cout << std::endl;
}

注意,为方便起见,代码依赖于Boost来计算二项式系数(boost::math::binomial_coefficient<T>),并将字符串解析为整数(boost::lexical_cast)。

答案 1 :(得分:1)

以下是Mathematica中的一个实现,来自包Combinatorica。语义是相当通用的,所以我认为它是有帮助的。如果您需要任何解释,请发表评论。

UnrankKSubset::usage = "UnrankKSubset[m, k, l] gives the mth k-subset of set l, listed in lexicographic order."

UnrankKSubset[m_Integer, 1, s_List] := {s[[m + 1]]}
UnrankKSubset[0, k_Integer, s_List] := Take[s, k]
UnrankKSubset[m_Integer, k_Integer, s_List] := 
       Block[{i = 1, n = Length[s], x1, u, $RecursionLimit = Infinity}, 
             u = Binomial[n, k]; 
             While[Binomial[i, k] < u - m, i++]; 
             x1 = n - (i - 1); 
             Prepend[UnrankKSubset[m - u + Binomial[i, k], k-1, Drop[s, x1]], s[[x1]]]
       ]

用法如下:

UnrankKSubset[1, 4, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}]
   {1, 2, 3, 5}

如您所见,此功能可在集合上运行。


以下是我尝试解释上面的代码。

UnrankKSubset是一个带有三个参数的递归函数,称为(m,k,s):

  1. m一个整数,从零开始的词汇顺序组合的“等级”。
  2. k一个整数,每个组合中的元素数量
  3. s一个List,用于组合组合的元素
  4. 递归有两个边界条件:

    1. 对于任何排名m,以及任何列表s,如果每个组合k中的元素数量为1,则:

      将列表m + 1中的s元素返回到列表中。

      + 1是必需的,因为Mathematica从一个索引,而不是零。我相信C ++这将是s [m])

    2. 如果排名m0,那么对于任何k和任何s

      返回k

    3. 的第一个s元素

      主递归函数,对于除上面指定的参数之外的任何其他参数:

      局部变量:(inx1u

      Binomial是二项式系数:Binomial[7, 5] = 21

      执行:

      i = 1
      n = Length[s]
      u = Binomial[n, k]
      While[Binomial[i, k] < u - m, i++];
      x1 = n - (i - 1);
      

      然后返回:

      Prepend[
        UnrankKSubset[m - u + Binomial[i, k], k - 1, Drop[s, x1]], 
        s[[x1]]
      ]
      

      也就是说,“prepend”列表x1的{​​{1}}元素(记住Mathematica索引来自一个,所以我相信这将是C ++中的s索引)返回的列表通过递归调用UnrankKSubset函数和参数:

      • x1 - 1
      • m - u + Binomial[i, k]
      • k - 1

      Drop[s, x1]是列表Drop[s, x1]的其余部分,其中删除了第一个s元素。


      如果上述任何内容无法理解,或者您想要的是对算法的解释,而不是对代码的解释,请发表评论,我会再试一次。