从整数向量生成大小k的下一个组合

时间:2016-10-04 04:31:15

标签: c++ algorithm math combinations combinatorics

假设我有一个大小为v = {0, 1,..., N-1}的整数N向量。

如果大小为k,我想生成所有k大小的v组合。

for example: k = 2, N = 10
    {0,1}, {0,2}, ..., {0,9}, {1,2}, ..., {8,9}

但我想逐个使用名为NextCombination的方法:

bool NextCombination(vector<int>& v, int k, int N){
    if( is not the last combination){
        turn v into it's next combination
        return true;
    }
    return false;
}

这意味着,鉴于当前状态v,组合的大小k和元素总数,我想更改v(如果可能) )并返回bool,表示可以从v中获得下一个组合。

如果没有一些无聊的递归,我无法弄清楚如何做到这一点,因为这只是我正在做的事情的小问题,我想找出一些智能/小解决方案。

2 个答案:

答案 0 :(得分:2)

您标记了C ++,因此最简单的方法是 - 使矢量长度为N,包含K个和(N-K)个零,如{1,1,0,0,0}并应用std::next_permutation

在每个步骤的位置显示 - 应该采取什么数字组合。

例如,排列{0,1,0,1,0}对应(1,3)组合。

修改

来自JörgArndtMatters Computational book的代码使用现成的K长度数组(格式和可读性差)

 void first()
 {
     for (ulong k=0; k<k_; ++k)  x_[k] = k;
 }

 ulong next()
 // Return smallest position that changed, return k with last combination
 {
     if ( x_[0] == n_ - k_ )  // current combination is the last
     { first();  return k_; }

     ulong j = k_ - 1;
     // easy case:  highest element != highest possible value:
     if ( x_[j] < (n_-1) )  { ++x_[j];  return j; }

     // find highest falling edge:
     while ( 1 == (x_[j] - x_[j-1]) )  { --j; }

     // move lowest element of highest block up:
     ulong ret = j - 1;
     ulong z = ++x_[j-1];

     // ... and attach rest of block:
     while ( j < k_ )  { x_[j] = ++z;  ++j; }

     return  ret;
 }

答案 1 :(得分:1)

就可读性而言,涉及MBo's answer的{p> std::next_permutation会更好。

然而,如果你真的想节省内存,那么你需要制作一个1和0的N大小的矢量。 以下解决方案基本上就地做了相同的事情。

bool NextCombination(vector<int>& v, int k, int N) {
  // We want to find the index of the least significant element
  // in v that can be increased.  Let's call that index 'pivot'.
  int pivot = k - 1;
  while (pivot >= 0 && v[pivot] == N - k + pivot)
    --pivot;

  // pivot will be -1 iff v == {N - k, N - k + 1, ..., N - 1},
  // in which case, there is no next combination.
  if (pivot == -1)
    return false;

  ++v[pivot];
  for (int i = pivot + 1; i < k; ++i)
    v[i] = v[pivot] + i - pivot;
  return true;
}