一.二进制的集合
for (int S1 = S; S1; (S1 - 1) & S)
S2 = S ^ S1;
其中是的子集,则是的补集.
下面我们证明一下为什么这样枚举是对的.
1.我们先证明这样枚举出来的集合都是的集合:
因为S1 & S,根据位运算的性质可知,S1必然是S的子集,证毕.
2.再证明为什么这样枚举可以枚举到所有的子集:
首先,S是自身的子集.其次是S1 - 1的作用.分情况讨论,如果当前的S1的最后一位是1,-1的作用就是把1变成0,经过&S之后,那么就是下一个小的集合了.如果当前的S1的最后一位是0,-1的作用就是让最后一位的1出现,经过&S后,也是下一个小的集合.由于集合是从大到小连续枚举的(从本身到0),所以能枚举完所有的集合,证毕.
二.普通的集合的枚举
我们可以采用二进制枚举(或者递归)
for (int i = 0; i < 1 << n; ++i)
for (int j = 0; j < n; ++j)
if (i >> j & 1)
//选
else
//不选