从n个数里面选k个数,状态压缩的方法求解

从n个数(0到n-1)里面挑选k个数,求所有选的方法,并且方法按照字典序升序排列。
比如n等于4,k等于2.
那么,就有
1 0
2 0
2 1
3 0
………以此类推
在网上看到一个用状态压缩解决的方法。
首先,讲n个数对应到二进制的01上面
n=4的时候,4 3 2 1,分别对应着二进制的第4位,第3位,第2位,最低位。
假设当前找到了0101.那么找到下一个数的时候,应当首先找一个尽量低位的0,让这个0变成1。这样就多了一个1,让后面的1减少一个就好了。可以变成1的0就是倒数第二位的那个0,将后面的1减少一个,就变成了0110。
下面的问题就是如何找到这个0。这个0如果可以变成1,相当于后面的1向前移了一位。那么也就是说,找到一个0,这个0后面有至少一个1,并且这个0的位置越低越好。
(图片来自互联网)
图片来自互联网
用comb表示当前这个数。
x表示当前数的最低位的1。学过树状数组的差不多都知道。
y就将前面说的那个可以变的0给变成了1,并且将这个0后面的全部变成0,相当于是将要求的下一个数中,这个0以及这个0前面的都给找出来了。
假设0110,那么可以变的0就是最高位的0,x就是0010,y是1000。
将y取反,再跟comb相与,就将可以变的0前面的都给变成0了(包括这个0),后面的给保存下来了。
那么,剩下的就是求这个0后面的部分了。由于将0变成了1,1的个数增加了一个,那么就要在这个0后面减少一个。由于有一个0变成1了,那么后面的这一部分当然越小越好。也就是说,剩下的几个1全部放在最低位最好。
这里很容易想象出来,comb最低位的1和可以变的0之间,必定全部都是1。那么,这样的话,就只需要将可以变的0后面的数右移,移到消失一个1为止就好了。
comb& ~y找出了可以变的0后面的部分,这部分一定是
………………0111……1000……0
第一个0代表可以变的0,后面跟着一串1,再后面跟着一串0。因为可以变的0前面都变成0了,那么第一个0前面的省略号里面全部都是0。
将这些1向右移,直到最低位的1移出去为止。
(comb& ~y)/x 将最低位的1移到了二进制的个位。再向右移一位,就是想要的结果。所以,(comb& ~y)/x >> 1就求出了可以变的0后面的样子。y保存了可以变的0以及可以变的0左边的样子。这样,就求出了下一个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值