枚举集合(子集)的子集(位运算)

题目

给定n个元素,问这n个元素组成的每一个集合的所有子集。(不妨n<=15)

思路来源

https://www.cnblogs.com/MyNameIsPc/p/8876855.html

https://www.jianshu.com/p/cfe562dcf2f6(反证法证明 枚举的是全部子集)

代码

for (int S=1; S<(1<<n); ++S){
    for (int S0=S; S0; S0=(S0-1)&S)
        //do something.
}

考虑S的子集,在二进制上从大到小排成一排,那么大的通过减若干个1就一定能到小的,

但是中间会产生大量的状态,这些状态中包含了一些S中不包含的1,故和S与一下,去冗即可,

从而每两个相邻的状态就都是S的子集,由于降序从而任意两个状态不重复,即任意子集状态均可达

 

注意到如果是S0-=lowbit(S0)操作的话,应该写作S0=(S0-1)&S0,每次少一个最右的1

而这里的区别是S0=(S0-1)&S,能起到枚举所有子集的作用,递减序枚举

 

暴力两层S<(1<<n)与S0<(1<<n)的复杂度是O(2^{2n}),而这样做的复杂度是所有元素个数,O(3^n)

 

如果不包括S自身,则先变小一步即可

for (int S=1; S<(1<<n); ++S){
    for (int S0=(S-1)&S; S0; S0=(S0-1)&S)
        //do something.
}

心得

18CCPC秦皇岛需要用到这个,然而当时不会

19南昌邀请赛斯坦纳树用到了这个,然而看了cls的代码也看不懂

后来发现,这个东西叫做枚举集合的子集,感觉好神奇……

复杂度

n位选出k位的方案数有C_{n}^{k}个,k位的子集个数有2^k

所有集合的子集的元素个数和为\sum_{k=0}^{n}C_{n}^{k}*2^{k} (不妨k=0也计算在内)

\sum_{k=1}^{n}C_{n}^{k}*1^{n-k}*2^{k},二项式定理知为O(3^n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值