P 1036选数

题目连接:https://www.luogu.org/problemnew/show/P1036

题目描述

已知 n 个整数 x1,x2,…,xn以及1个整数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个整数(满足条件的种数)。

输入输出样例

输入样例#1: 复制

4 3
3 7 12 19

输出样例#1: 复制

1

详细题解在代码里

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n, k, a[21], s, ans;
bool f[21];
int isprime(int n)//判断是否是质数的一个函数,不需多解释,i的范围到sqrt(n),是为了降低时间复杂度
{
    for(int i = 2; i <= sqrt(n); ++i)
    {
        if(n%i == 0)
            return 0;
    }
    return 1;
}
int rule(int x, int y)//x表示已经选了几个数,y为选第几个数,从y到n是为了避免重复的出现,例如1234中选3个,已经选了123
//与124,准备为13选下一个数,如果从1到n开始循环,则程序会到2,而2也是合适的,但这样就与123重复了,所以从y开始
{
    for(int i = y; i <= n; ++i)
    {
        if(f[i] == true)//表示该数没有被选过,则执行if语句,
        {
            f[i] = false;//标志该数已经被选过,
            s += a[i];//将对应的值加到s中
            if(x == k)//当已经加到了k个,
            {
                if(isprime(s))//就判断这个和是否是质数,是的话那么就加1
                    ans += 1;
            }
            else//表示还没加到k个数,则继续搜寻下一个数,所以x+1,i+1是为了搜寻当前数的下一个数,避免重复,
                rule(x+1, i+1);
            s -= a[i];//回溯,s的值减去当前值a[i],这个语句要放在else之外,因为x==k时也无法继续搜寻,需要回溯,
            f[i] = true;//标志为没有被选过
        }
    }
}
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[i]);//依次读入这些数
        f[i] = true;//标志为没有被选过
    }
    rule(1, 1);//从选了一个数,选第一个数开始调用函数
    printf("%d\n", ans);//输出最终的结果,也就是多少个符合质数。
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_31038073/article/details/87942031