【问题标题】:Generate next combination of size k from integer vector从整数向量生成下一个大小为 k 的组合
【发布时间】:2016-10-04 04:31:14
【问题描述】:

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

给定k 的大小,我想生成v 的所有k 大小的组合。

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 中得到一些下一个组合是可能的。

如果没有一些无聊的递归,我无法弄清楚如何做到这一点,而且由于这只是我正在做的事情的一个小问题,我想找出一些聪明/小的解决方案。

【问题讨论】:

  • 从 v 中获得下一个组合是什么意思?
  • 我的意思是如果 k = 2 和 N = 4,我从向量 {0,1} 开始,nextCombination 会将它变成 {0,2},然后变成 {0,3},然后 { 1,2},然后是 {1,3},然后是 {2,3},最后返回 false

标签: c++ algorithm math combinations combinatorics


【解决方案1】:

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

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

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

编辑

来自 Jörg Arndt 的 Matters 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;
 }

【讨论】:

  • K 大小的向量(而不是 N 大小的二进制向量)中的实际值没有任何办法吗?这种方式会使我的应用程序变慢,因为必须查看比必要更多的对象(例如,找到 N = 100 的 3 个对象并不好)
【解决方案2】:

就可读性而言,涉及std::next_permutationMBo's answer 更好。

但是,如果您真的想节省内存,则需要制作一个包含 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;
}

【讨论】:

  • 正如我所说,这只是一个小问题(在另一个更大的交易中),只要它运行良好,它的可读性并不重要。这完成了工作,谢谢!
  • 这是这里最简单但最有效的解决方案。
猜你喜欢
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
  • 2018-03-21
  • 2019-05-16
相关资源
最近更新 更多