zoukankan      html  css  js  c++  java
  • 通过位操作来实现组合算法

    这篇文章简直就是位操作的练习,各种位操作都使用到了。

    主要思想是将n选m表示为一个长度为n的二进制串,1为选中,0为不选中。每次的结果都根据上一次生成的结果在常数时间生成的,即从右向左查找第一个01,将其变为10,并把这个位置往右的的1都推向最右边。初始的字符串1都在最右边,最后终止的时候1都在左边。

    代码如下,比较难懂。

     1 #include <stdio.h>
     2 #include <malloc.h>
     3 //这篇代码的适用范围是64位以内的组合问题,即0的个数与1的个数不超过64.虽然写代码的时候我只用32位,即int,为了偷懒。。。
     4 //每一个新的组合跟上一个的组合都是有关联的,即从右向左找第一个序列为01的对,然后将他变成10,并将这个01后面的1全都移到最右端,然后就生成了新的组合。
     5 //而且组合的生成序列是按照词法序的,每生成一个序列所需要的时间为常数
     6 #define ZERO 7
     7 #define ONES 3
     8 unsigned int countbits(unsigned int input)//得到一个二进制串中1的个数
     9 {
    10     unsigned int bits_counter = 0;
    11     bits_counter = input;
    12     bits_counter = (bits_counter & 0x55555555) + ((bits_counter >> 1) & 0x55555555);
    13     bits_counter = (bits_counter & 0x33333333) + ((bits_counter >> 2) & 0x33333333);
    14     bits_counter = (bits_counter & 0x0f0f0f0f) + ((bits_counter >> 4) & 0x0f0f0f0f);
    15     bits_counter = (bits_counter & 0x00ff00ff) + ((bits_counter >> 8) & 0x00ff00ff);
    16     bits_counter = (bits_counter & 0x0000ffff) + ((bits_counter >> 16) & 0x0000ffff);
    17     return bits_counter;
    18 }
    19 void outprint(unsigned int input)
    20 {
    21     unsigned int bit_count = 1<<31;
    22     while (bit_count >= 1)
    23     {
    24         printf("%d ", (bit_count&input) && 1);
    25         bit_count = bit_count >> 1;
    26     }
    27     printf("
    ");
    28 }
    29 int main()
    30 {
    31     unsigned int output;
    32     unsigned int part,next,temp1,temp2,end,bit_count_1,bit_count_2;
    33     int count = 0;
    34     output =( 1 << (ONES) )-1;//initial
    35     end = output << ZERO;
    36     while (output != end)//这里以例子0101100000来说明
    37     {
    38         outprint(output);
    39         count++;
    40         part = (output - 1) ^ output;//这里首先获得output 0101100000的最后的连续的0,当末尾是100000时,我们将会得到111111
    41         bit_count_1 = countbits(part)-1;//通过这一步我们得到了output末尾0的个数 这里为5
    42         next = part | output;//通过这步,我们把output末尾的连续的0都变成了1,0101100000会变成0101111111
    43         temp1 = (next + 1) ^ next;//通过这一步,我们把end 0101111111变成了0011111111,即把output从右往左数第一个以01为前缀的后缀全都变成了1
    44         bit_count_2 = countbits(temp1) - 2;//通过这一步,我们得到了从右往左数第一个01 中的1的后面的位数,这里为6
    45         bit_count_2 = bit_count_2 - bit_count_1;//这样我们就得到了01后面1的个数 这里为1
    46         temp2 = temp1 - (temp1>>1);//通过这一步我们把temp1的第二个1及以后的所有位变成了0得到了0010000000
    47         temp2 = temp2 | ((1 << bit_count_2) - 1);//将这个01后面的1都放到最右边去,生成新的后缀0010000000变成了0010000001
    48         output = output&(~temp1);//通过这一步,我们把output第一个01及以后的数全都清0,output变成了0100000000
    49         output = output | temp2;//然后将两端组合起来,最后得到了0110000001
    50         
    51     }
    52     outprint(output);
    53     count++;
    54     printf("%d
    ", count);
    55 }
  • 相关阅读:
    国内外常用学术论文搜索网站
    2019年全国高校sql数据库
    Flask无法访问(127.0.0.1:5000)的问题解决方法
    Windows终端命令行工具Cmder
    JQuery实现密码可见不可见
    区块链最大的难题及其解决方案
    python 下载 进度条
    centos 用docker 运行 cypress
    通过 centos Nginx 查看html (为后续 服务器生成html 方便访问)
    odoo 分享 PostgreSQL 语句2
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3459292.html
Copyright © 2011-2022 走看看