给力!高效!易懂!位运算求组合

 

本篇摘要

本篇介绍一个非常给力的求组合的算法!上一篇“c_c++刁钻问题各个击破之位运算及其实例(2)”介绍了6个比较复杂的位操作,但是没有给出任何应用实例,本篇就之前谈到的位操作进行应用,其主要内容是用位操作来实现求组合

引例

先来看一道题目,这个题目是理解利用位操作求组合的关键。它是POJ的2453。英文原题就不贴了,我用中文描述一下吧:给定一个正整数N,求最小的、比N大的正整数M,使得M与N的二进制表示中有相同数目的1。

上面的题目描述或许有点拗口,举个例子把,假如给定的N为78,其二进制表示为1001110,包含4个1,那么最小的比N大的并且二进制表示中只包含4个1的数是83,其二进制是1010011,因此83就是答案。那么如何求解这个问题呢?这里给出两个思路:

(1) 最直观的思路:枚举

思路是从N+1开始枚举,对每个数都测试其二进制表示中的1的个数是否与N的二进制表示中1的个数相等,遇到第一次相等时就停止。其算法流程如下:

1、  求得N的二进制表示中1的个数k;

2、  N++;

3、  测试N的二进制表示中所包含的1的个数是否等于k,如果是,则输出N后结束,否则转2;

上面的过程可以用如下的流程图来表示:

用代码实现上述流程如下:

int GetNextN(unsigned int N)
{
    int k = count1Bits(N);
    do
    {
        N++;
    }while(count1Bits(N)!=k);
    return N;
}


    上面的代码中还有一个问题没有解决,那就是“求整数的二进制表示中有多少个1”即count1Bits()函数。这个问题在我之前的《c/c++刁钻问题各个击破之位运算及其实例(1)》中有详细阐述,它应用了n&=(n-1)能将n的二进制表示中的最右边的1翻转为0的事实。只需要不停地执行n&=(n-1),直到n变成0为止,那么翻转的次数就是原来的n的二进制表示中1的个数,其代码如下:

int count1Bits(unsigned int n)
{
    int count = 0;
    while(n)
    {
        count++;
        n&=(n-1);
    }
    return count;
}


 

至此,第一个枚举方法介绍完毕,你只需要写如下的main()函数就能测试本方法:

void main()
{
    int N;
    cin>>N;
    cout<<
  • 15
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值