状态压缩
假设有n个物品,那么对于这n个物品的集合的子集要如何表示呢?
可以用一个整型数字来表示,当这个数的二进制的第i位为1时表示,第i个物品在这个整数表示的集合里,反之如果为0则不在,通过这个方式,一个有n个数的集合的任意子集就都能用一个整数表示出来了。
对于一个有n个元素的集合,它的非空子集有2^n-1个,对应数字范围为 1……2^n - 1
对于二进制集合j 第i位取到1表示集合j有第i个元素,否则没有
以下是遍历出集合j的所有子集z
for(int z = 1;z <= sz;z++)//sz是集合j的最高位1
int x = ((1<<z) - 1)&j;//1<<z - 1的前z位都是1所以只能求出j的部分子集,例如
//1<<z - 1 = (0000 1111)2 j = (0000 1101)2 x = (0000 1101)2 会漏掉
//子集1001 1100 1000 所以错误
for(int z = 1;z <= j;z++)
z = z&j;//当z = (00000001)2 j = (00000100)2 时z 会一直是0 从而导致死循环,错误
for(int z = 1;z <= j;z++)
int x = z&j;//简单朴素的方法 不漏掉每个可能的子集
for(int z = j;z;z = (z-1)&j)//z - 1会保证 z 一直递减且-1递减过程不会跳过j的其他子集,并且&保证z是j的子集,直接让z = j的下一个子集,所以比上一个方法更快