位运算枚举子集模板
给定n个元素,问这n个元素组成的每一个集合的所有子集;
for(int s=0;s<(1<<n);++s){
for(int sub=s;sub;sub=(sub-1)&s){
//do something
}
}
原理是这样的;
集合S的任何一个子集,在二进制表示下,必然可以通过若干次-1
得到;
那按照这个思路,我们的算法流程如下;
假设S0 = S,S0为要枚举的子集,S为集合;
- S0 - 1
- 判断S0是否是S的子集
那么我们可以加速这个过程,通过&
来加速;
因为我们的判断就是集合S中某些为0的位上,S0却是1;
而按位与自然就可以来操作这个过程;
并且还有一个性质,我们枚举的子集必然是按递减顺序得到的;
因为减一之后得到的必定是数值上最接近同时也小于等于子集S0的值。
进一步使用集合S进行与运算后,只是为了约束得到的子集S0只保留所需要的位,那么是显然是较大的数值能够最大化的匹配这些保留的位吧;