集合的表示及其运算
来源:互联网 发布:windows管道通信 编辑:程序博客网 时间:2024/05/01 07:22
说明:当状态的维数比较多,但每个维数都只有两种情况时,可以考虑用集合来表示。下面来说明集合的表示及其运算。
一,集合的表示及基本操作
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独立出来后的值,设为xint y = s + x;//根据第二步的描述,令s+x即可实现,设结果为ys = ((s&~y) / x >> 1) | y;//s&~y恰好只剩下最低位的1开始的连续区间,其他地方都为0,假设这个结果是z,那么(z/x)>>1就是第三步的结果,再与y取或,即完成了第四步}
0 0
- 集合的表示及其运算
- 集合表示及其运算(持续更新)
- 整数的补码表示及其运算分析
- 离散数学实践:集合的表示与运算
- 位运算-集合的整数表示
- 位运算--集合的整数表示
- 位运算表示集合的整数
- 【数据结构】树与树的表示、二叉树存储结构及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树与哈夫曼编码、集合及其运算
- 集合及其运算-prolog
- [汇编]数的补码表示及其加减运算
- 数据结构笔记(一)线性表的顺序表示和基本操作及其顺序表实现的集合运算(A-B)U(B-A)实例
- 第二章模糊集合及其基本运算+第三章模糊集合的其他运算
- 集合的表示、并查集的数组存储方式和集合的差并运算
- 用位向量实现的集合及其常用运算
- java位运算及其四则表示
- 集合的二进制表示。
- 集合的整数表示
- 集合的二进制表示
- Linux下字节对齐准则
- 不可滚动的ListView
- ConnectivityManager源码分析
- 黑马程序员--面向对象(Java)
- java网络编程基础夯实03-为什么不能直接通过IP访问网站
- 集合的表示及其运算
- opencv进行图像复原
- 回调函数
- socket阻塞与非阻塞,同步与异步、I/O模型
- [LeetCode] 031. Next Permutation (Medium) (C++/Python)
- LeetCode #189 Rotate Array
- 一个程序员的自我修养:为什么我这么低端
- (hdu step 5.2.3)Phone List(Trie实现:在一堆号码中,判断是否有号码是其他号码的前缀)
- WebView基本使用