二进制枚举
已知n个整数x1, x2, .., xn,以及一个整数k,k < n。从n个数字
中任选k 个整数相加,可分别得到一系列的和。
例如当n = 4, k = 3,四个整数分别为3,7,12,19时,可得全部的组合与他们的和为:
3 + 7 + 12 = 22
3 + 7 + 19 = 29
7 + 12 + 19 = 38
3 + 12 + 19 = 34
现在,要求计算出和为素数的组合共有多少种。例如上例,只有一种组合的和为素数:3 + 7 + 19 = 29
1 ≤ n ≤ 20, k < n
1 ≤ x1, x2, .., xn ≤ 5 * 10^6
首先我们来考虑如何枚举这样的组合。
我们用ai来表示第i个数是否被选:ai = 1表示这个数被选择了;ai =0表示这个数未被选择
枚举过程相当于枚举了一组二进制状态
比如对于五个数1,2,3,4,5
01010表示我们选择了2,4,未选择1,3,5
在不考虑k的限制的情况下,我们枚举所有组合就相当于枚举00..00(n个0) → 11..11(n个1)
对于任意一种中间状态,0的个数+1的个数为n。
我们假设这是一个长为n的二进制数,我们将它转换成十进制。
事实上就是枚举了一个数,范围是[ 0, 2^n )
判断位置i是否为1使用位运算来完成
#include<iostream> #include<cmath> using namespace std; int n,k; int num[21]; int ans; bool check( int n ){ int t=sqrt(n); for( int i=2 ; i<=t ; ++i ){ if( n%i==0 ) return 0; } return 1; } int main(){ cin>>n>>k; for( int i=1 ; i<=n ; ++i ){ cin>>num[i]; } for( int i=0 ; i<( 1<<n ) ; ++i ){ int tmp=0,sum=0; for( int j=0 ; j<n ; ++j ){ if( (1<<j)&i ){ tmp++; sum+=num[j]; } } if( tmp==k ) ans+=check(sum); } cout<<ans; return 0; }