状压DP 学习笔记

一、基础位操作

具体技巧 核心用途 位运算表达式/实现 说明/原理
判断第i位是否为1 检查元素i是否在集合中(如城市是否已访问) (mask & (1 << i)) != 0 1<<i生成第i位为1的掩码,按位与非0则第i位为1
第i位置1 将元素i添加到集合中(如选择任务i) `mask = (1 << i)`
第i位清0 将元素i从集合中移除(如回溯取消选择) mask &= ~(1 << i) ~(1<<i)第i位为0、其余为1,按位与清0第i位
第i位翻转 切换元素i的状态(选/不选、占用/释放) mask ^= (1 << i) 异或1翻转第i位,异或0保留其余位

[========]

| 集合运算 | 判断两个集合无交集 | 检查两个状态是否无冲突(如任务不重叠)| (a & b) == 0 | 无任何一位同时为1,说明无公共元素 |
| 集合运算 | 求两个集合并集 | 合并两个状态的所有元素 | a | b | 按位或保留所有为1的位,即两个集合的全部元素 |
| 集合运算 | 求两个集合交集 | 提取两个状态的公共元素 | a & b | 仅保留同时为1的位,即公共元素 |
| 集合运算 | 枚举集合所有非空子集 | 枚举当前状态的前驱/子集(DP转移核心)| ```c++
for (int sub = mask; sub; sub = (sub - 1) & mask) {
// 处理子集sub
}

| 集合运算         | 枚举集合所有真子集           | 枚举不含自身的子集                         | ```c++
for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {
  // 处理真子集sub
}
``` | 初始为最大真子集,后续逻辑同非空子集枚举                                |
| 集合运算         | 判断a是否为b的子集           | 检查a的元素全包含在b中                     | `(a & b) == a`                                                                   | 若a是b的子集,a与b的交集仍等于a                                          |
| 计数与状态提取   | 统计掩码中1的个数            | 获取集合大小(如已访问城市数)| C++:`__builtin_popcount(mask)`<br>Python:`bin(mask).count('1')`                 | 手动实现:循环执行`mask &= mask-1`,每轮清除最低位1并计数                |
| 计数与状态提取   | 提取最低位的1(LSB)| 找到集合中最小的元素(如最后选择的任务)| `lowbit = mask & (-mask)`                                                         | 补码特性:-mask = ~mask + 1,按位与仅保留最低位1                          |
| 计数与状态提取   | 清除最低位的1                 | 移除集合中最小的元素(如回溯取消最后选择)| `mask = mask & (mask - 1)`                                                        | mask-1将最低位1置0,按位与清除该位                                       |
| 计数与状态提取   | 提取最高位的1(MSB)| 找到集合中最大的元素(如最早选择的任务)| C++:`1 << (31 - __builtin_clz(mask))`                                            | `__builtin_clz`统计前导0个数,计算最高位1的位置                          |
| 进阶优化技巧     | 掩码范围限制                 | 仅保留前n位有效位(避免无关位干扰)| `mask & ((1 << n) - 1)`                                                          | `(1<<n)-1`生成前n位全1的掩码,按位与清除n位后的所有位                    |
| 进阶优化技巧     | 异或表示状态差异             | 计算两个状态的差异位(新增/删除的元素)| `diff = a ^ b`                                                                    | 异或结果中1的位置,即为两个状态的差异位                                  |
| 进阶优化技巧     | 预处理合法掩码               | 过滤不符合约束的状态(减少DP状态量)| 提前筛选满足条件(如1的个数为k)的掩码存入数组                                   | 避免DP遍历过程中重复判断约束,提升效率                                    |
posted @ 2025-11-30 16:24  Ty_66CCFf  阅读(1)  评论(0)    收藏  举报