在解决物品选择问题的时候,当物品的数量比较少的时候,我们可以把每个物品看做一个二进制位,0和1表示选与不选两种情况,暴力枚举所有情况以解决问题。
每个二进制位有两种情况,时间复杂度为O(2^n),2^25≈3*1e7。
要实现上述操作,我们需要判断每个二进制位的数值情况,在c++中,可以用>>与&运算符实现:
操作1:>>,将一个数的二进制形式后右移一位。例如:9=b(1001),9>>1就得到b(100),即4;
操作2:&,判断一个数的二进制形式的末尾一位是否为1。例如:9=b(1001),9&1等于1。
枚举0~(2^n)-1,即可枚举到n个物品的所有选择情况,每种情况下通过>>与&判断每个物品的选择情况。
代码模板如下:
//输出0~(2^x)-1(x个物品)的二进制形式
#include<iostream>
#include<cmath>
using namespace std;
int main() {
int x;
cin >> x;//假设有x个物品
for (int i = 0; i < pow(2,x); i++) {//一共x个二进制位
for (int j = 0; j < x; j++)//右移j位
cout << ((i >> j) & 1) << " ";
cout << endl;
}
return 0;
}
当输入x=3,即有三个物品时,枚举了有三个物品时的所有选法。
例题:
给出长度为n的数组,求能否从中选出若干个,使他们的和为K.如果可以,输出:Yes,否则输出No。
输入:
第一行:输入N,K,为数组的长度和需要判断的和(2<=N<=20,1<=K<=10^9);
第二行:N个值,表示数组中元素的值(1<=a[i]<=10^6)。
输出:
输出Yes或No。
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
const int N=30;
int q[N];
int main(){
int n,k;
cin>>n>>k;
for(int i=0;i<n;i++)cin>>q[i];
for(int i=0;i<pow(2,n);i++){
int tmp=0;
for(int j=0;j<n;j++)
if((i>>j)&1)tmp+=q[i];
if(tmp==k){cout<<"Yes";return 0;}
}
cout<<"No";
return 0;
}