状压 dp 枚举子集原理
for(int S1=S;S1!=0;S1=(S1-1)&S){ S2=S^S1; }
其中 就是我们枚举得到的子集, 是 在 内的补集,即 。
赘述如下:
现在来讲一讲为什么是这样的一个枚举方法,先让我们来举一个例子来模拟一下。
假设我们当前要枚举的是 的子集(子集仍然用 表示):
根据例子,我们发现按照上面代码得到的结果是正确的,并且是把子集按照从大到小的顺序枚举出来的。
那么接下来我们来谈谈这样枚举的正确性。
首先,一个集合它自己本身也是自己的一个集合,所以我们从这个集合本身开始枚举。
既然是枚举,那我们就先考虑把当前枚举得到的子集先 ,但是这样做不能保证−1后得到的状态是原状态的子集,
但是我们注意到:根据与运算&的性质,我们不难发现如果两个数 ,我们对这两个数进行&运算,最后的结果一定是b的子集,因为我们与运算&得到的结果,在二进制中出现 的位, 中一定也是1。
现在已经说明了这样做确实得到了原集合的子集,但是还没有说明我们已经枚举完了原集合的子集。
其实枚举子集就相当于在原集合的二进制状态下把一些 换为 ,
而我们每次 然后进行与运算其实就是在把当前子集的最右边的1的右边全部变为 ,自己变为 ,
然后进行与运算把新增的1中不该出现的抹去,最后只剩下了原集合中存在的 了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效