原题链接:https://www.luogu.com.cn/problem/P1036
题意解读:题目即要在n个数中,枚举出所有的子集,当子集中数字个数刚好为k时,求和,判断是否是素数。
解题思路:
方法一:二进制法
通过二进制法,可以枚举一个集合中所有元素“选”或者“不选”的情况,用二进制1表示选该元素,二进制0表示不选。
下面对样例数据进行模拟:
如上图,从上到下依次枚举0~24-1对应的二进制,根据二进制位的0/1来决定对应元素“选”或“不选”,
k=3的即二进制位有3个1的情况用绿色标识,求和后是素数的用红色标识。
因此对于一般的n个数,只需要枚举0~2n-1,判断每个数的二进制中1的个数是否为k,再针对每个二进制位是0或1决定选或不选对应元素。
这里就引出两个重要的二进制操作:
1、统计二进制有多少个1
首先,介绍一个关键的操作:lowbit,可以返回一个数的二进制中最后一个1所表示的整数
例如x=6,即二进制0110,lowbit(6) = 2,实现如下:
int lowbit(int x)
{return x & -x;
}
要计算一个数的二进制中有多少个1,只需要每次都减去这个数的lowbit,直到0为止,统计次数:
int count1(int x)
{int cnt = 0;while(x){x -= lowbit(x);cnt++;}
}
2、二进制的某一位是0还是1
设整数i,要判断第j个(最低位j=0)二进制位是0还是1,只需要判断i >> j & 1是0还是1
100分代码-二进制法:
#include <bits/stdc++.h>
using namespace std;const int N = 25;int n, k, ans;
int a[N];//计算x的二进制中最后一个1所代表的整数,如11000回返回1000,也就是8
int lowbit(int x)
{return x & -x;
}//计算x的二进制中有多少个1
int count1(int x)
{int cnt = 0;while(x){x -= lowbit(x);cnt++;}return cnt;
}//判断x是否是素数
bool isprime(int x)
{if(x < 2) return false;for(int i = 2; i * i <= x; i++){if(x % i == 0) return false;}return true;
}int main()
{cin >> n >> k;int pow2n = 1;for(int i = 0; i < n; i++){cin >> a[i];pow2n *= 2; // 计算2^n } for(int i = 0; i < pow2n; i++){ if(count1(i) == k) //如果整数i的二进制中1的个数==k{int sum = 0;for(int j = 0; j < n; j++) //遍历二进制的每一位{if(i >> j & 1) sum += a[j]; //i >> j & 1表示将i右移j位再和1求&,即判断i的第j位二进制是否是1,注意j=0表示第一位}if(isprime(sum)) ans++;}}cout << ans; return 0;
}
方法二:DFS
n个数字,每个数字只有选或者不选两种情况,可以用一个数组保存选择的状态,1表示选,0表示不选,通过DFS来填充此数组即可。
100分代码-DFS:
#include <bits/stdc++.h>
using namespace std;const int N = 25;int n, k, ans;
int a[N];int tmp[N];//判断x是否是素数
bool isprime(int x)
{if(x < 2) return false;for(int i = 2; i * i <= x; i++){if(x % i == 0) return false;}return true;
}void dfs(int level)
{if(level > n) // 找到一组选择{//判断是否有k个1int cnt = 0;for(int i = 1; i <= n; i++){if(tmp[i] == 1) cnt++;}if(cnt != k) return;int sum = 0;for(int i = 1; i <= n; i++){if(tmp[i] == 1) sum += a[i];}if(isprime(sum)) ans++;return;}for(int i = 0; i <= 1; i++){tmp[level] = i;dfs(level + 1);}
}int main()
{cin >> n >> k;for(int i = 1; i <= n; i++) cin >> a[i];dfs(1);cout << ans;return 0;
}