让咱们从一个题目入手c++
从一个大小为n的整数集中选取一些元素,使得它们的和等于给定的值T。每一个元素限选一次,不能一个都不选。spa
关于这个题目,咱们很容易想到的即是对全部元素进行暴力搜索,而后进行剪枝即可。code
下面我将介绍二进制枚举的思路和流程来巧妙的解决这个问题。ci
对任一数来讲,所面临的问题是取或不取,在二进制中即可以用1或0来表示。因为每一个数都会对应一串二进制数字,那么结果便有2^n个状态,如1000001便相对于取0号位元素和最后一号元素,其余元素不取。那么咱们能够枚举这2^n个状态,经过遍历当前状态的每一位来判断,而后对取的元素求和判断是否为一个合格的状态。it
#include <bits/stdc++.h> using namespace std; #define ll long long #define ld long double const int maxn = 2005; int a[maxn], n, t, cnt; int main() { cin >> n; for(int i = 0; i < n; i++) cin >> a[i]; cin >> t; for(int i = 1; i < (1 << n); i++) { int sum = 0;//元素和 for(int j = 0; j < n; j++) { if(i & (1 << j))//判断当前状态i的二进制数第j位是否为1,取或不取 sum += a[j]; } if(sum == t)//知足条件记录 { for(int j = 0; j < n; j++) { if(i & (1 << j)) cout << a[j] << " "; } cout << endl; cnt++;//记录合理数 } } cout << cnt << endl; }
看完上面代码,有些小伙伴就要问了,i&(1<<j)是什么。模板
那么补充一波位运算的知识吧:class
按位与运算符(&)搜索
参加运算的两个数据,按二进制位进行“与”运算。遍历
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;二进制
即:两位同时为“1”,结果才为“1”,不然为0
例如:3&5 即 0000 0011& 00000101 = 00000001 所以,3&5的值得1。
左移运算(<<)
a << b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。能够看出,a << b的值实际上就是a乘以2的b次方,由于在二进制数后添一个0就至关于该数乘以2(这样作要求保证高位的1不被移出)。
一般认为a << 1比a * 2更快,由于前者是更底层一些的操做。所以程序中乘以2的操做请尽可能用左移一位来代替。注意:不要用于浮点数类型
最后,给出二进制的基本模板
for(int i = 0; i < (1<<n); i++) //从0~2^n-1个状态 { for(int j = 0; j < n; j++) //遍历二进制的每一位 { if(i & (1 << j))//判断二进制第j位是否存在 { //进行操做 } } printf("\n"); }