状态压缩(初识)

注意:状态压缩的集合是无法满足贪心的排序的

一.了解状态压缩之前需要知道的几点

1.(k&-k)在状态压缩和树状数组中都经常能够看到,那么(k&-k)的值是什么含义呢?

这个值是把k的二进制的高位1全部清空,只留下最低位的1,当然如果只有一位1,则保留等于k本身。该操作就是留下k二进制数中最低位的一个1

2.两种相等的形式:i-(i&-i) = i^(i&-i)

他们都表示减去最低位的1,再返回值

3.状态压缩的方法,就是利用二进制数的零一进行模拟。零代表没取,一代表取了。时间复杂度O(2^n)只能用在n小于20的情况下。首先在存储每个元素的时候就按照(1,10,100,1000)的方法来存储,需要枚举所有的子集时可以利用sum[i] = sum[i-(i&-i)] + a[i & -i] 每个sum[i],都表示i在二进制中1取零不取。可以进行初始化,算出每个i的二进制一的个数。

4.代码:

    //bc[i]表示i的二进制表示中一的个数是多少
    bc[0] = 0;
    for (i=1; i<(1<<20); i++)
        bc[i] = bc[i-(i&-i)] + 1;

 for (i=0; i<m; i++) scanf("%d", &tmp[1<<i]);//tmp存储的时候就是按照1左移存储的

        sum[0] = 0;
        for (i=1; i<(1<<m); i++)
            sum[i] = sum[i-(i&-i)] + tmp[i&-i];/*每次都保证减去最低位后的状态是已经求出的,或者状态是空sum[0]。比如从1000开始到1001(1000求出)到1010(1000求出)到1011(减去最低位后为1010也已求出)。那么为什么地位减去后一定是已求出的呢,因为减去小于其本身,sum[i]又是顺序遍历的
        此处还有问题,为什么是不重不漏的呢?每次到临界值(1,10,100,1000)时sum[i]的值都等于tmp[i].当减去最低位后,不肯能是等于它本身的,此时又再加上了另一个数,
        注意此处的1,0是二进制。实际上是sum[1] = tmp[1],sum[10] = tmp[10],sum[11] = sum[10] + temp[1] = temp[10] + temp[1],以此类推sum[1111] = temp[1] + temp[10] + temp[100] + temp[1000]
        其实很简单的啦,每次sum[i]表示的都是对于i的二进制数来说0,代表取到1代表取不到。肯定是全部的状态(不包括都取不到的,那种是sum[0]的情况)*/


5.一定要注意的问题:

原数组,存储所有子集的数组,还有用来存储任意个数二进制个数的数组大小都要开到2^n次方。另,当n <= 20时,时间空间都可以容纳2^20

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值