状态压缩 求以二进制表示的集合的所有子集

状态压缩

假设有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的下一个子集,所以比上一个方法更快
                 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值