二進制枚舉

讓咱們從一個題目入手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");
    }
相關文章
相關標籤/搜索