洛谷P1036 选数(回溯法)
题目描述
已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4 个整数分别为 3,7,12,19 时,可得全部的组合与它们的和为:3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34。
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29)。
输入输出格式
输入格式:
键盘输入,格式为:n , k (1<=n<=20,k<n)
x1,x2,…,xn (1<=xi<=5000000)
输出格式:
屏幕输出,格式为:一个整数(满足条件的种数)。
输入输出样例
输入样例#1:
4 33 7 12 19
输出样例#1:
1解题分析
用回溯法求从1~n中取k个不同数的不同组合,然后求以这些组合为下标的k个数之和,判断其是否为素数。可以利用测试法判断某个数是否为素数。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 22
int n, k, x[N], y[N], used[N], ans = 0;
void get_i(int &x) {
char ch = getchar();
x = 0;
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
}
// 快速幂
int qmod(int a, int x1, int x) {
long long tmp;
if(x1==1)
return a;
else if(x1==0)
return 1;
tmp = qmod(a, x1>>1, x);
if(x1&1)
return ((tmp * a) % x * tmp) % x;
return (tmp * tmp) % x;
}
// 测试法判定x是否为素数
int isPrime(int x) {
int a, t = 4;
srand(time(NULL));
while(t--) {
a = rand() % (x - 1) + 1;
if(qmod(a, x-1, x)!=1)
return 0;
}
return 1;
}
int judge() {
int i, tmp = 0;
for(i=1; i<=k; i++)
tmp += x[y[i]];
return isPrime(tmp);
}
void dfs(int m) {
int i;
if(m==k+1) { // 得到一个组合
ans += judge();
return;
}
for(i=y[m-1]; i<=n; i++) {
if(!used[i]) {
y[m] = i;
used[i] = 1;
dfs(m+1);
used[i] = 0;
}
}
}
int main() {
ios::sync_with_stdio(false);
int i;
get_i(n), get_i(k);
for(i=1; i<=n; i++)
get_i(x[i]);
y[0] = 1;
dfs(1);
cout<