子集枚举 二进制
子集枚举之二进制法(好土的名字)
A中元素 | 1 | 2 | 3 | 4 | 5 | 二进制 |
---|---|---|---|---|---|---|
在\(A_1\)中的出现情况 | 1 | 0 | 1 | 1 | 1 | 11101 |
在\(A_2\)中的出现情况 | 1 | 0 | 0 | 1 | 1 | 11001 |
在\(A_3\)中的出现情况 | 0 | 0 | 1 | 0 | 0 | 00100 |
在\(A_4\)中的出现情况 | 0 | 1 | 1 | 0 | 0 | 00110 |
仅包含第\(i(1\le i \le 5)\)个元素的集合的数字可以用位移运算构造,写成1<<(i-1)
;包含所有元素的全集为u=(1<<n)-1
,空集表示为0。
一些集合的常用关系有以下几种:
- 并集。从元素的选择角度来讲,就是\(A_2\)与\(A_3\)包含的元素合并起来得到\(A_1\)。可以发现,这就是按位或的运算,可表示为
a1 = a2 | a3
。 - 交集。2个集合中同时存在的元素组成的集合。当需要表示2个集合的交集时候,可以把表示2个集合的二进制数按位与运算,即
a3 = a1 & a4
。 - 包含。集合\(A_2\)的所有元素都在\(A_1\)中出现,说明\(A_1\)包含\(A_2\)。判断\(A_1\)是否包含\(A_2\)可以写成
(a1|a2 == a1) && (a1&a2 == a2)
。 - 属于。把某个元素看做为1个集合,取交集检查是否为1即可。如判断第3个元素是否属于集合\(A_1\)可以写成
(1<<(3-1)) & a1
。 - 补集。\(A_2\)对于全集的补集就是\(A_4\),可以写成
a4 = a^a2
,^
为c/c++异或符号。
统计二进制中的1的个数可以使用内建函数 __builtin_popcount()
,它能返回一个数二进制数下1的个数;当然也可以逐位确认。
不忘初心方得始终