洛谷P1036 选数(回溯法)

本文解析洛谷P1036选数问题,介绍如何使用回溯法找出所有可能的组合,并通过测试法判断组合之和是否为素数,最终计算出符合条件的组合数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

洛谷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 3
3 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<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值