集合枚举的意思是从一个集合中找出它的所有子集。集合中每个元素都可以被选或不选,含有n个元素的集合总共有个子集(包括全集和空集)
例如考虑集合和它的4个子集、、、,按照某个顺序,把全集A中的每个元素在每个子集中的出现状况用0(没出现)和1(出现了)表示出来。
A中元素 | 1 | 2 | 3 | 4 | 5 | 二进制 | 对应十进制 |
在A1中的出现情况 | 1 | 0 | 1 | 1 | 1 | 11101 | a1=29 |
在A2中的出现情况 | 1 | 0 | 0 | 1 | 1 | 10011 | a2=25 |
在A3中的出现情况 | 0 | 0 | 1 | 0 | 0 | 00100 | a3=4 |
在A4中的出现情况 | 0 | 1 | 1 | 0 | 0 | 00110 | a4=6 |
通过上面的表格就可以发现A的子集A1可以表示为一个二进制数11101,对应十进制变量a1=29,反之,这个数字也可以表示子集A1。注意,这边的集合是大写字母,集合对应的数字是小写字母。同理,A2可以表示为二进制数11001。此时找到了一种让子集对应于二进制数的很直观的方法
本例一共有5个元素,表示仅包含第i个元素的集合的数字可以使用位移运算构造,写成1<<(i-1),即,例如要找仅包含第3个元素的集合,那么找a=1<<(3-1),也就是4,此时对应的二进制数为00100,也就是集合{3}。而包含所有元素的全集可以表示成a=(1<<n)-1,空集表示为0。
一些常用的集合关系:
(1)并集:从元素选择角度来说,就是A2、A3包含的元素合并起来能够得到A1。可以发现A1的每一位都等于A2 or A3的结果。变成验证可得a1=a2|a3。只需要把表示两个子集的二进制数进行或运算即可得到两个子集的并集。
(2)交集:是指两个集合中同时存在的元素组成的集合。类似前面的并集运算,当需要两个子集的交集时,可以把表示两个子集的二进制数进行与运算,即a3=a1&a4。
(3)包含:集合A2的所有元素都在A1中出现,说明A1包含A2。易知A1并A2是A1,同时A1交A2是A2,也就是判断A1是否包含A2可以写成(a1|a2==a1)&&(a1&a2==a2)
(4)属于:是指某个元素在集合中,是包含的一种特殊情况--只需检查单独某项元素构成的集合是否是另一个集合的子集。一般地,可以使用户左移运算构造出那个仅含一项的集合,然后再和原集合取交,若不为空集,则命题为真。如果要判断第3个元素是否属于A1,可以写成1<<(3-1)&a1
(5)补集:是指全集去除了某个集合后剩下元素组成的集合。可以使用异或运算来表示集合对全集的补集,例如A2对于全集的补集就是A3。A2的补集可以表示为a^a2。
注意:枚举子集的时间复杂度是,一般情况下1秒钟可以枚举包含20-30个元素的集合的子集。
具体的例题运用,可以参照此专栏的题解。
P1036 [NOIP2002 普及组] 选数题解-CSDN博客
P1157 组合的输出题解-CSDN博客