给集合里的元素一个顺序,那么就可以用整数表示集合,某一位为1表示对应元素被选取。
设x为表示集合的整数,那么这个整数有如下性质:
x的子集整数y在数值上不会比x大。因为x的子集y只是保留了x某些位置上的1,所以y总可以加上一个非负的整数z等于x,相当于把没选的1补上。
根据这个性质可知,可以通过枚举所有比x小的数p并判断,p是否只含x对应位上的1,如果是则p是x的子集,否则不是。这样时间复杂度是严格的x。有没有更快的呢,有的。
上诉枚举p是通过减一操作,并且我们知道减一操作一定是正确的,那么在枚举的时候如何快速的去掉多余的状态,答案就是和x进行&(与)运算。与运算可以快速跳到下一个子
集。
&运算本质就是保留p在x对应位为1的数值,而根据二进制减法可知减一操作都是把p最低位的1消去,在那一位后全补上1,如果在x对应位为0的地方产生了1其实是无效的,
后续的减一操作也会把它消掉,所以直接&运算可以快速去掉多余的状态。时间复杂度是x的子集数。
代码如下:
for(int i=x;i;){
i=(i-1)&x;
}