讓咱們從一個題目入手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"); }