zoukankan      html  css  js  c++  java
  • 枚举子集的几种方法

    程序设计挑战竞赛上156页说了枚举组合和子集的几种方法,我觉得挺好的,收藏一下

    都是利用二进制数的模型来进行枚举子集或者组合

    下面枚举集合都是在二进制位上进行枚举。

    ##枚举k个数的子集

    void EunmSet(int k)//用k个二进制位数枚举k个状态
    {
        for(int i=0;i<1<<k;++i)
        {
            // 对子集的处理
        }
    }
    

    当k等于3时,即EunmSet(3)

    输出:

    000
    001
    010
    011
    100
    101
    110
    111

    枚举一个二进制状态的子集(其实我更喜欢for循环枚举)

    void EnumSubSet(int sup)/*作用:对于二进制状态sup,枚举该状态的子集*/
    {
        int sub=sup;
        do{
            /*对子集的处理*/
            sub=(sub-1)&sup;
        }
        while(sub!=sup);/*当sub=0之后 sub=0-1=-1,退出*/
    }
        /*
        原理:针对sup中的二进制为1的位开始进行减法,假设有k个二进制位,那么像枚举(2^k-1)~0一样枚举其子集
        输出:
            状态为降序输出
        */
    

    当sup=10101,即十进制数21

    输出:

    10101
    10100
    10001
    10000
    00101
    00100
    00001
    00000

    枚举n个状态中,k个状态成立的所有状态

    void EnumK(int k,int n)/*求出总共n个状态中,有k个状态为1的所有情况*/
    {
        int comb=(1<<k)-1;
        while(comb<1<<n)//comb>=2^n退出
        {
            //针对组合的处理
            int x=comb&-comb,y=comb+x;
            comb=((comb&~y)/x>>1)|y;
        }
    }
        /*原理:
            根据当前的符合要求的状态求出第一个大于该状态的符合要求的状态
        输出:
            升序输出
         算法描述:
         按照字典序的话,最小的子集是(1<<k)-1,所以用它作为初始值。现在哦我们求出comb其后的二进制码
         1.求出最低位的1开始连续的1的区间  (x&(-x)的值就是将最低位的1独立出来的值)
         2.将这一区间全部变为0,并将区间最左侧的0变为1
         3.将第1步取出的区间右移,知道剩下的1的个数少了1个
         4.将第2步和第3步的结果按位取或
        */
    

    输入:k=3,n=5

    00111
    01011
    01101
    01110
    10011
    10101
    10110
    11001
    11010
    11100

  • 相关阅读:
    VS2005 Web安装程序 创建程序菜单组
    文件夹 文件 加入/去除 Everyone全控
    [转]asp.net 部署数据库、开始菜单、桌面快捷方式实例
    身边的贵人
    AppCode下的cs类 取得相关路径
    遭遇“windows已经阻止此软件因为无法验证发行者”
    成功不是忽悠
    关于 软件注册授权 防止被大面积免费扩散 的设想
    [转]获取机器的硬件信息(CPU ID序列号, 主板信息,硬盘序列号,系统信息)
    递交辞呈之后
  • 原文地址:https://www.cnblogs.com/dchnzlh/p/10427230.html
Copyright © 2011-2022 走看看