子集是一个数学概念:如果集合A的任意一个元素都是集合B的元素,那么集合A称为集合B的子集。
A集合有n个元素,那么A的子集个数为2n。
我们先来看看3个物品的23取法分别是哪8种
取法\物品 | 物品1 | 物品2 | 物品3 |
---|---|---|---|
取法1 | 0 | 0 | 0 |
取法2 | 0 | 0 | 1 |
取法3 | 0 | 1 | 0 |
取法4 | 0 | 1 | 1 |
取法5 | 1 | 0 | 0 |
取法6 | 1 | 0 | 1 |
取法7 | 1 | 1 | 0 |
取法8 | 1 | 1 | 1 |
我们在表格后面再加上两项来观察一下
取法\物品 | 物品1 | 物品2 | 物品3 | 对应二进制 | 对应二进制数 |
---|---|---|---|---|---|
取法1 | 0 | 0 | 0 | 000 | 0 |
取法2 | 0 | 0 | 1 | 001 | 1 |
取法3 | 0 | 1 | 0 | 010 | 2 |
取法4 | 0 | 1 | 1 | 011 | 3 |
取法5 | 1 | 0 | 0 | 100 | 4 |
取法6 | 1 | 0 | 1 | 101 | 5 |
取法7 | 1 | 1 | 0 | 110 | 6 |
取法8 | 1 | 1 | 1 | 111 | 7 |
显然,任何一种取法都可以用n位二进制数表示,也就是说,[0,2n-1]这2n个数的二进制表示分别对应了2n种取法
代码实现:
int main()
{
int n;
cin >> n; //n个物品
for (int i = 0; i < (1 << n); i++) //遍历每种取法对应的二进制数i
{
for (int j = 0; j < n; j++) //遍历i的每一位
{
if ((i >> j) & 1) //如果取法i的第j位是1,那么表示取法i要取第j个物品
cout << j + 1 << " ";
}
cout << endl;
}
return 0;
}