zoukankan      html  css  js  c++  java
  • 集合的整数表示与子集枚举

    集合{0,1,…,n-1}的子集S可以编码成整数:f(S)=∑2i,像这样表示之后,一些集合运算可以对应地写成如下方式:

    ①空集Ø:……………………………………………0

    ②只含有1个元素i的集合{i}…………………………1<<i

    ③含有全部n个元素的集合…………………………(1<<n)-1

    ④判断第i+1个元素i是否属于集合S………………if (S>>i&1)

    ⑤向集合中加入第i+1个元素i(S∪{i})…………S|1<<i

    ⑥从集合中取出第i+1个元素(S{i})……………S&~(1<<i)

    ⑦集合S和集合T的并集S∪T………………………S|T

    ⑧集合S和集合T的交集S∩T………………………S&T
    此外,想要将集合{0,1,…,n-1}的所有自己枚举出来的话,可以这样写:

    for (int S=0; S<1<<n; S++)
    {
        //对子集的处理
    }

    接下来,介绍如何枚举某个集合sup的子集。这里sup是一个二进制码。

    (sub-1) & sup

    (sub-1)&sup会忽略sup中的0而从sub中减去"1",最终sub可以将sup所有的子集按照降序生成出来。为什么不能用加?因为(sub+1)&sup虽然是sup的子集,但很可能依旧是sub,没有任何改变,而用减就不会出现这样的情况。

    int sub=sup;
    do
    {
      //对子集进行处理  
      sub=(sub-1)&sup;
    } while (sub != sup);//处理完0之后,会有-1&sup=sup

    最后,介绍如何枚举{0,1,…,n-1}所包含的所有大小为k的子集。通过位运算,按照字典序升序地枚举出所有满足条件地二进制码,先上代码:

    复制代码
    int comb = (1<<k)-1;
    while (comb< 1<<n)
    {
        //这里进行针对组合的处理
        int x=comb&(-comb), y=comb+x;
        comb=((comb&~y)/x>>1)|y;
    }
    复制代码

    按照字典序的话,最小的子集是(1<<k)-1,所有用它作为初始值,下面就要求出comb之后一个二进制码了,方法如下:
    ①求出最低位的1开始的连续的1的区间(0101110→0001110)
    ②将这一区间全部变为0,并将区间左侧的那个0变为1(0101110→0110000)
    ③将第①步里取出的区间右移,直到剩下的1的个数减少了1个(0001110→0000011)
    ④将第②步和第③步的结果按位取或(0110000|0000011→0110011)
    对于非零的整数,x&(-x)的值就是将其最低位的1独立出来的值,即lowbit

    除上述例子外,还可以利用位运算完成满足其它条件的集合的枚举,例如不包含相邻元素的集合等

  • 相关阅读:
    [转]批处理for命令使用指南
    批处理命令学习
    【树】Count Complete Tree Nodes
    【树】Flatten Binary Tree to Linked List(先序遍历)
    【树】Kth Smallest Element in a BST(递归)
    巧用border特性实现聊天气泡效果
    【树】Lowest Common Ancestor of a Binary Tree(递归)
    【树】Path Sum II(递归)
    【树】Populating Next Right Pointers in Each Node
    【树】Serialize and Deserialize Binary Tree
  • 原文地址:https://www.cnblogs.com/Ymir-TaoMee/p/9509521.html
Copyright © 2011-2022 走看看