生成所有可能的组合

时间:2011-08-29 11:57:36

标签: algorithm combinatorics

我正在编写一些代码并最终解决了这个问题。我有N个产品,我必须形成这些产品的所有可能组合,形成产品目录并找到一些属性,如价格。为了做到这一点,我必须从给定的产品中形成产品目录(详尽,但不允许重复)。这样做有标准化的算法吗?请注意,目录可以包含任何正数的产品。

4 个答案:

答案 0 :(得分:4)

组合可以用位向量表示。如果设置了某个位,则该元素将出现在组合中。

所以你只需要enumarte从1到2 ^ N-1(从0000001,最后一个元素到1111111,所有元素都存在)的所有数字,并代表一个可能的组合。

答案 1 :(得分:2)

从给定字符串中打印所有字符组合的简单实现:

void print_combination(char* str, char* buffer, int len, int num, int pos)                                                                 
{
  if(num == 0)
  {
    std::cout << buffer << std::endl;
    return;
  }

  for(int i = pos; i < len - num + 1; ++i)
  {
    buffer[num - 1] = str[i];
    print_combination(str, buffer, len, num - 1, i + 1);
  }
}

int main()
{
  char str[] = "abcde";
  char buffer[6];
  for(auto i = 1u; i <= sizeof(str); ++i)
  {
    buffer[i] = '\0';
    print_combination(str, buffer, 5, i, 0);
  }
}

非常简单但可能存在性能问题。如果可以的话,请接受它。

如果您正在寻找排列(我无法从您的描述中得知),我在“计算机编程艺术”中实现了算法:

template <typename Iter>                                                                                                                   
bool next_permutation(Iter start, Iter end)
{
  if(start == end)
    return false;

  Iter i = start + 1;
  if(i == end)
    return false;

  i = end - 1;

  while(true)
  {
    Iter ii = i;
    --i;
    if(*i < *ii)
    {
      Iter j = end;
      while(*i >= *--j);
      std::iter_swap(i, j);
      std::reverse(ii, end);
      return true;
    }
    if(i == start)
    {
      std::reverse(start, end);
      return false;
    }
  }
}

int main()
{
  char str1[] = "abcde";
  do
  {
    std::cout << str1 << std::endl;
  } while(next_permutation(&str1[0], &str1[5]));
}

它非常有效,C ++ stl算法使用相同的算法。

答案 2 :(得分:2)

您可以在python中使用itertools.combinations以下列方式执行此操作:

import itertools

products = ['p1', 'p2', 'p3', 'p4']
for L in range(1, len(products)+1):
      for subset in itertools.combinations(products, L):
              print(subset)

结果如何:

('p1',)
('p2',)
('p3',)
('p4',)
('p1', 'p2')
('p1', 'p3')
('p1', 'p4')
('p2', 'p3')
('p2', 'p4')
('p3', 'p4')
('p1', 'p2', 'p3')
('p1', 'p2', 'p4')
('p1', 'p3', 'p4')
('p2', 'p3', 'p4')
('p1', 'p2', 'p3', 'p4')

this answer of @dan-h启发的解决方案。

答案 3 :(得分:1)

计算机程序设计艺术的前几部分,第一卷。 3,排序和搜索非常详细地讨论了反转和置换(集合和多集)。在这种情况下,重要的是在理论上考虑一下,看看那里有什么。代码将遵循,但如果这是“休闲时间编码”,为什么不包括“休闲时间理论”呢? Betcha它会很酷,你会知道什么,但你也会知道这些为什么!