在为编程比赛(如ACM,Code Jam等)练习时,我遇到了一些问题,需要我生成一些矢量元素的所有可能组合。
假设我有向量{1,2,3},我需要生成以下组合(顺序并不重要):
1
2
3
1 2
1 3
2 3
1 2 3
到目前为止,我已经使用以下代码完成了它:
void getCombinations(int a)
{
printCombination();
for(int j=a;j<vec.size();j++)
{
combination.pb(vec.at(j));
getCombinations(j+1);
combination.pop_back();
}
}
调用getCombinations(0);为我做的工作。但是有更好(更快)的方式吗?我最近听说过bitmasking。据我所知,它仅仅适用于1到2 ^ N-1之间的所有数字,我将该数字转换为二进制数,其中1和0表示该元素是否包含在组合中。
我如何有效地实现这一点?如果我以标准方式将每个数字转换为二进制(通过一直除以2)然后检查所有数字,这似乎浪费了很多时间。有没有更快的方法?我应该继续使用递归(除非我遇到一些递归无法完成工作的大数字(堆栈限制))?
答案 0 :(得分:3)
您可以获得的组合数量为2 ^ n,其中n是您的元素数量。您可以将0到2 ^ n -1之间的每个整数解释为掩码。在您的示例(元素1,2,3)中,您有3个元素,因此掩码将是000,001,010,011,100,101,110和111.让掩码中的每个位置代表您的一个元素。对于具有1的位置,取相应的元素,否则如果该位置包含0,则将该元素保留。例如,数字5将是掩模101,并且它将生成该组合:1,3。
如果你想拥有一个快速且相对较短的代码,你可以这样做:
#include <cstdio>
#include <vector>
using namespace std;
int main(){
vector<int> elements;
elements.push_back(1);
elements.push_back(2);
elements.push_back(3);
// 1<<n is essentially pow(2, n), but much faster and only for integers
// the iterator i will be our mask i.e. its binary form will tell us which elements to use and which not
for (int i=0;i<(1<<elements.size());++i){
printf("Combination #%d:", i+1);
for (int j=0;j<elements.size();++j){
// 1<<j shifts the 1 for j places and then we check j-th binary digit of i
if (i&(1<<j)){
printf(" %d", elements[j]);
}
}
printf("\n");
}
return 0;
}