[技巧]枚举子集的飘逸写法

鸟泉学长告诉我的,今天想到了就顺便记上。

设S表示一个01状态集,那么它的所有非空子集x可以通过以下代码枚举。

for (int x = S; x; x = (x-1)&S)


简单说明下原理(证明以后补上?):

x = (x-1)&S实际上是把S中的0全部忽略,并不断减1的结果,比如S=1011,则x分别为:1011, 1010, 1001, 1000, 0011, 0010, 0001。忽略S中第二位的0其实就是111, 110, 101, 100, 011, 010, 001。

称S中的1所在位为有效位,0所在位为无效位,则x中的无效位必为0,有效位为0或1,比如S=1011,x=1001(有效位加下划线)。-1就是加上-1补码1111…,可以想成把无效位的1先加上去,比如x=1001变成1101,再加有效位的1。由于无效位加完肯定是1,会把有效位的进位“传递”下去,然后再位与S使得无效位变成0,实际就相当于有效位加上1111…,也就是有效位-1。

posted @ 2012-01-16 18:13  杂鱼  阅读(...)  评论(...编辑  收藏