【问题标题】:Iterating over subsets of any size迭代任意大小的子集
【发布时间】:2009-11-05 20:10:11
【问题描述】:

我可以遍历大小为 1 的子集

for( int a = 0; a < size; a++ ) {

或大小为 2 的子集

for( int a1 = 0; a1 < size; a1++ ) {
    for( int a2 = a1+1; a2 < size; a2++ ) {

或 3

for( int a1 = 0; a1 < size; a1++ ) {
for( int a2 = a1+1; a2 < size; a2++ ) {
   for( int a3 = a2+1; a3 < size; a3++ ) {

但是如何对大小为 n 的子集执行此操作?

这是根据 Adam Rosenfield 的回答完成的

void iterate(int *a, int i, int size, int n)
{
 int start = 0;
 if( i > 0 ) start = a[i-1]+1;
 for(a[i] = start; a[i] < n; a[i]++) {
  if(i == n-1) {
      // a is the array of indices of size n
      for( int k = 0; k < size; k++ ) {
          printf("%d ",a[k]);
      }
      printf("\n");
  }
        else
            iterate(a, i+1, size, n);
    }
}

标签: c++ algorithm


【解决方案1】:

你可以使用递归:

void iterate(int *a, int i, int size, int n)
{
    for(a[i] = 0; a[i] < size; a[i]++)
    {
        if(i == n-1)
            DoStuff(a, n);  // a is the array of indices of size n
        else
            iterate(a, i+1, size, n);
    }
}
...
// Equivalent to 4 nested for loops
int a[4];
iterate(a, 0, size, 4);

【讨论】:

  • 这很有趣。然而 a[i] > a[j] 其中 i>j 没有被强制执行
  • 但是如果我添加这个: int start = 0; if( i > 0 ) 开始 = a[i-1]; for(a[i] = start;a[i]
  • 糟糕!应该是 int start = 0; if( i > 0 ) 开始 = a[i-1]+1; for(a[i] = start;a[i]
  • 需要进行更多更改。 for 循环的最大值应该是 n,而不是 size。通过这些更改,该算法可以在生产代码中运行并通过单元测试!谢谢。
【解决方案2】:

您可能可以通过一些递归来做到这一点。

【讨论】:

  • 这是对每个问题的有效答案。你可以用递归做任何事情!
【解决方案3】:

这是我用来解决类似问题的东西。它不使用递归;相反,它使用索引向量。

#include <vector>

template<class T>
class MultiForVar {
std::vector<T> _begin, _end, _vars;
inline int dim(){return _vars.size();}
public:
MultiForVar(std::vector<T> begin, std::vector<T> end) : _begin(begin), _end(end), _vars(_begin)
{
  assert(begin.size() == end.size() and "Starting and ending vector<T> not the same size!" );
}
MultiForVar& operator ++()
{
  ++_vars[dim()-1];
  for(int d = dim()-1; d > 0; --d)
  {
    if( _vars[d] >= _end[d] )
    {
      _vars[d] = _begin[d];
      ++_vars[d-1];
    }
  }
  return *this;
}
bool done()
{
  /*for(int d = 0; d < dim(); ++d)
    if( _vars[d] < _end[d] )
      return false;
  return true;*/
  return (_vars[0] >= _end[0]);
}
T operator[](int d)
{
  return _vars.at(d);
}
int numDimensions(){
  return dim();
}
std::vector<T>& getRaw(){
  return _vars;
}

};

【讨论】:

    【解决方案4】:

    如果我理解您的要求正确,另一种方法是使用按位运算符:

    for(int i = 0; i < 1<<size; i++) {
        for(int j = 0; j < size; j++) {
           if(i & 1<<j) printf("%d ", a[j]);
        }
        printf("\n");
    }
    

    【讨论】:

      【解决方案5】:

      你需要一些东西来构建原始集合的幂集。我已经有一段时间没有写了,但是伪代码看起来像

      Powerset(a, size)
      {
         if(size == 0) return emptyset
      
         subseta = Powerset(a, size-1) // Powerset of everything except last element
         subsetb = appendToAll(a[size-1], subseta) // appends the last element to every set in subseta
         return union(subseta, subsetb)
      }  
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-08
        • 2019-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多