集合的表示及其运算
2015-03-07 16:09
267 查看
说明:当状态的维数比较多,但每个维数都只有两种情况时,可以考虑用集合来表示。下面来说明集合的表示及其运算。
空集:0
全集:(1<<n)-1
只含有第i个元素的集合{i}:1<<i
判断第i个元素是否属于集合{0,1……n-1}:if((S>>i)&1)
向集合中加入第i个元素S∪{i}:S|=1<<i
从集合中除去第i个元素S\{i}:S&~(1<<i)
集合S和T的并集S∪T:S|T
集合S和T的交集S∩T:S&T
集合S为全集,s为其一个子集,s的补集:s^S
(1)求出最低位的1开始的连续的1的区间,例如(0101110->0001110)
(2)将这一区间全部变为0,并将区间左侧的那个0变为1,例如(0101110->0110000)
(3)将第一步里取出的区间右移,直到剩下的1的个数减少了1个,例如(0001110->0000011)
(4)将第二步和第三步的结果按位取或(取并集),例如(0110000|0000011=0110011)
根据上述的步骤,不难写出如下的代码,注意每一步的写法。
一,集合的表示及基本操作
C语言中集合采用二进制码来表示,相当于将集合编码成一个整数。利用公式f(S)=∑2^i(i∈S)即可将集合编码成为一个整数。下面假设集合中一共有n个元素,编号从0开始。空集:0
全集:(1<<n)-1
只含有第i个元素的集合{i}:1<<i
判断第i个元素是否属于集合{0,1……n-1}:if((S>>i)&1)
向集合中加入第i个元素S∪{i}:S|=1<<i
从集合中除去第i个元素S\{i}:S&~(1<<i)
集合S和T的并集S∪T:S|T
集合S和T的交集S∩T:S&T
集合S为全集,s为其一个子集,s的补集:s^S
二,枚举子集
枚举子集可以采用从大到小逆序枚举(因为顺序枚举有很多缺陷)。假设全集为S,令s为S的子集,那么最初令s=S,之后每次减一,由于减掉之后可能不是S的子集,因此应该再取交集:(s-1)&S。由此不难写出枚举的代码:for (int s = S; s >= 0; s = (s - 1)&S) { //对子集的处理 }
三,枚举集合{0,1……n-1}所包含的所有大小为k的子集
按照字典序的话,最小的子集是(1<<k)-1,因此用它作为初始值,每次都求出子集s的下一个子集。方法如下:(1)求出最低位的1开始的连续的1的区间,例如(0101110->0001110)
(2)将这一区间全部变为0,并将区间左侧的那个0变为1,例如(0101110->0110000)
(3)将第一步里取出的区间右移,直到剩下的1的个数减少了1个,例如(0001110->0000011)
(4)将第二步和第三步的结果按位取或(取并集),例如(0110000|0000011=0110011)
根据上述的步骤,不难写出如下的代码,注意每一步的写法。
int k,n; int s = (1 << k) - 1; while (s < 1 << n) { int x = s&-s;//s&-s的值就是将最低位的1独立出来后的值,设为x int y = s + x;//根据第二步的描述,令s+x即可实现,设结果为y s = ((s&~y) / x >> 1) | y;//s&~y恰好只剩下最低位的1开始的连续区间,其他地方都为0,假设这个结果是z,那么(z/x)>>1就是第三步的结果,再与y取或,即完成了第四步 }
相关文章推荐
- 数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算
- 集合表示及其运算(持续更新)
- 数据结构笔记(一)线性表的顺序表示和基本操作及其顺序表实现的集合运算(A-B)U(B-A)实例
- 集合及其运算-prolog
- 多项式及其运算(用单链表表示)
- 数据结构 用单链表表示集合的并交差运算
- 离散--第一节--逻辑符号 + 集合及其运算 + 证明方法概述
- 初学Python——集合及其运算
- 用位向量实现的集合及其常用运算
- 整数的补码表示及其运算分析
- [汇编]数的补码表示及其加减运算
- python入门(九):集合及其运算
- 位运算--集合的整数表示
- 21天学通C++之集合的链表实现及其运算实现
- 第二章模糊集合及其基本运算+第三章模糊集合的其他运算
- 离散数学实践:集合的表示与运算
- 位运算表示集合的整数
- 集合的表示、并查集的数组存储方式和集合的差并运算
- java集合框架集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
- java位运算及其四则表示