子集的生成—二进制枚举

有这样的一个问题:

给定一个集合,让你输出所有的子集。

这时候二进制就派上了用场~

我们用0,1来表示当前位是否被保留,值为1则保留,为0则舍弃 ,如下图所示:

那么对于一个有n个数的集合来讲,每一位有取和不取两种状态,一共就有2n种状态,我们可以从0一直枚举到2n来表示所有子集的状态。

但是现在问题又来了,对与我们枚举的数,你怎么知道哪一位是0,哪一位是1?

这个时候就要用到位运算的知识了,对于一个数S(子集的状态)我们拿它和0~n每一位i进行S&(1<<i)这样的运算就能得到对于的位是否为1(&运算符的特点是只有当对应位都为1时,运算结果才为1)

举个栗子,S = 13,对于的二进制码为1101

1101 & 0001得到第一位为1

1101 & 0010得到第二位为0

1101 & 0010得到第三位为1

1101 & 1000得到第四位为1

这样就得到我们取集合中的1,3,4位

实现代码:

for(int i = 0; i < (1<<n); i++) //二进制枚举每一个状态
    for(int j = 0; j < n; j++) //枚举该状态下二进制的每一位数值
        if(i&(1<<j)) //当前位是否为1
            printf("%d ", a[j]);

原文地址:https://www.cnblogs.com/wizarderror/p/11364958.html

时间: 2024-11-12 21:32:32

子集的生成—二进制枚举的相关文章

1151 - Buy or Build(二进制枚举子集 + 并查集)

这题LRJ书上翻译的有问题,书上说两点之间的cost是两点的欧几里得距离,而题目要求两点的距离是两点欧几里得距离的平方. 其余就没什么好说的了,裸的并查集,需要注意的就是二进制枚举子集的问题. 二进制枚举子集: for(int i = 0 ; i < (1 << s) ; i++){ /*s是集合元素的个数*/ for(int j = 0 ; j < s ; j++){ if(!(s >> j) & 1) continue; else{ } } } 140548

【UVA】11464-Even Parity(二进制枚举子集)

枚举第一行的所有可能情况,之后根据上面行计算下面行(判断是否冲突),获得最终结果. 14058243 11464 Even Parity Accepted C++ 0.275 2014-08-18 05:14:15 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<stack> #inc

做实验 解题报告(二进制枚举子集)

题目描述 有一天,你实验室的老板给你布置的这样一个实验. 首先他拿出了两个长度为 n 的数列 a 和 b,其中每个 a i 以二进制表示一个集 合.例如数字 5 = (101) [2] 表示集合 {1, 3}.第 i 次实验会准备一个小盒子,里面装 着集合 a i 所有非空子集的纸条.老板要求你从中摸出一张纸条,如果满足你摸出的 纸条是 a i 的子集而不是 a i?b i ,a i?b i +1 ,...,a i?1 任意一个的子集,那么你就要被阿掉; 反之,你就逃过一劫. 令你和老板都没有想

(二进制枚举子集)买玩具

问题描述 蒜厂幼儿园有 n 个小朋友,每个小朋友都有自己想玩的玩具.身为幼儿园园长的你决定给幼儿园买一批玩具,由于经费有限,你只能买 m 个玩具.已知玩具商店一共卖 k 种玩具,编号为 1,2,3,…k,你让每个小朋友把想玩的玩具编号都写在了纸上.你希望满足尽可能多的小朋友的需求,请计算出最多同时能满足多少个小朋友的玩具需求. 输入格式 第一行,输入三个整数 n,m,k(1≤n≤100,1≤m≤k≤15),中间用空格分开. 接下来 n 行,第 i+1(0≤i< n) 行的第一个数字 ai代表第

UVa 818 切断圆环链(dfs+二进制枚举)

https://vjudge.net/problem/UVA-818 题意:有n个圆环,其中有一些已经扣在了一起.现在需要打开尽量少的圆环,使得所有圆环可以组成一条链,例如,有5个圆环,1-2,2-3,4-5,则需要打开一个圆环,如圆环4,然   后用它穿过圆环3和圆环5后再次闭合4,就可以形成一条链:1-2-3-4-5. 思路:从n个圆环中任意选择圆环,这就是枚举子集.所以这道题目可以用二进制枚举来做. 那么如何判断当前打开圆环是可行的呢?在去除打开的圆环后需要判断: ①:每个圆环的分支数都必

关于二进制枚举

算是彻底搞懂二进制枚举吧. 首先一个集合的子集有2^n个,所以我们枚举的个数有(1<<n)个: 所以 for(int i=0; i<(1<<n); i++) 我们知道二进制枚举的过程如下: 每个位置值为1则保留,不为1则舍弃 : 设s=13(二进制为1101)那么我们保留0 2 3位置上的数值: 那么我们如何找到每个位置上的数值呢? 我们遍历的是二进制的十进制表示(比如13),我们当然可以转化为二进制在枚举每一位,但是,这很麻烦: 一个很巧妙的方式就是利用位运算: 1<

南阳OJ-91-阶乘之和---二进制枚举(入门)

题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=91 题目大意: 给你一个非负数整数n,判断n是不是一些数(这些数不允许重复使用,且为正数)的阶乘之和,如9=1!+2!+3!,如果是,则输出Yes,否则输出No:n<1000000; 思路: 数据量小,直接预处理出所有满足的数,然后直接判断就行了,预处理时用了二进制枚举子集的方式来处理 1 #include<iostream> 2 #include<cstdio>

UVa818 Cutting Chains (二进制枚举)

链接:http://vjudge.net/problem/35523 分析:links记录初始圆环链的情况,然后二进制枚举编号为0~n-1的圆环哪个被打开了,一个圆环最多一个前驱和一个后继,所以judge判断如果有一个未打开的圆环同时和2个以上的未打开圆环相连就一定不能形成链,剪去.circle判断剩下的未打开圆环是否形成环,以及若未成环那么有多少条单链links_num,注意最后成链不用按顺序比如1->2->3...这样.然后判断一下打开的圆环数够不够把links_num条单链扣成一条链,若

Boost的某些库还是需要生成二进制的库的,必须安装才行,以及使用库的方法

头文件就是库使用者最常问的问题就是“我该怎么安装Boost”,这个也是我一开始最关心的问题,Boost这点做的很好,将大部分实现都封装在头文件里,所以对于一些基本的Boost库,其实是不需要安装的,只需要将头文件include到自己的程序里,当然前提是你把Boost的所有用到的头文件都拷贝了一份.Boost是如何做到这点的?这是因为Boost的头文件(*.hpp)包含了模板和内联函数,这点随便找一个hpp文件来看你就明白了,所以不需要去静态链接活动态链接二进制lib库了.不过Boost的某些库还