预备知识:
- 取n的第k位:(n>>i)&1
- 求 2 i 2^i 2i:1<<i
- 将n第i位变为1:n|(1<<i)
- 将n的第k位清0:n&~(1<<i)
- 取最低位的1:n&(-n)
将一个集合S用整数表示,即把S写成下面的形式:
S
=
∑
i
∈
S
2
i
S=\sum_{i\in S}2^i
S=∑i∈S2i
这样,如果第i位为1,说明第i个元素在S中,否则就不在其中。
根据上面的关系,我们可以得到以下结论:
如果枚举子集,可按照如下方式:
int k=S;
k=(k-1)&S; //除全集外的最后一个子集
while(k!=S) {
k=(k-1)&S; //上一个子集
}
这种方法会倒序枚举子集,之所以不采用正序的方式(即某个子集k的下一个子集为(k+1)&S),是因为这样做很可能导致k==S。