NOIP 2002 普及组 选数
题目大意
从一个有 n n n 个数的数列中选出 k k k 个互不相同的数 , 要使他们的和为一个质数 , 求一共有多少种选择的方法
题目分析
看到这道题的第一眼 , 我首先想到的是使用 C++ 中自带的 n e x t next next _ p e r m u t a t i o n permutation permutation 函数 , 但是试过之后发现,有的情况会被重复记录 , 造成答案偏大.这时我想到了另一种方法 : 递归.
既然使用自带的函数会因为数据重复记录造成重复 , 那么我们在写递归的时候就要注意数的排列顺序 , 也就是说 , 我们可以在输入之后对它进行排序,以达到不重复的目的
代码分析
这道题的核心代码主要是分为两部分:
判断质数
bool zhishu(int num){
if(num==0||num==1){
return 0;//质数特判:0和1不是质数
}
for(int i=2;i*i<=num;i++){
if(num%i==0){
return 0;//能整除,不是质数
}
}
return 1;
}
判断质数是竞赛中常用的子程序之一 , 在这里不过多解释了 , 主要强调一点 , 因为一个数的因数都是成对出现的 , 可以只枚举某个数的前一半因数 , 节省时间
递归代码
void zhaoshu(int geshu,int sum,int head){
//geshu:已经选了几个
//sum:当前的已经选好了的数的和
//head:下一个数的起始位置
if(geshu==k){//数已经选够了
if(zhishu(sum)==1){//满足题意
ans++;//结果数+1
}
return;
}else {//还不够
for(int i=head;i<=n;i++){
zhaoshu(geshu+1,sum+a[i],i+1);//递归:继续寻找
}
return;
}
}
这里我们定义了三个变量 : g e s h u , s u m , h e a d geshu ,sum,head geshu,sum,head , 这些变量都是用来记录我们找数过程中的信息的 . 只有良好的数据记录 , 才可以确保找数的时候不会重复
还有就是递归边界的设置 , 这里因为题目要我们找的是 k k k 个数 , 所以我们就可以把边界设为 g e s h u = = k geshu==k geshu==k ,等到找够了的时候就可以进行判断了
AC Code
#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[21];
int ans;
bool zhishu(int num){
if(num==0||num==1){
return 0;
}
for(int i=2;i*i<=num;i++){
if(num%i==0){
return 0;
}
}
return 1;
}
void zhaoshu(int geshu,int sum,int head){
if(geshu==k){
if(zhishu(sum)==1){
ans++;
}
return;
}else {
for(int i=head;i<=n;i++){
zhaoshu(geshu+1,sum+a[i],i+1);
}
return;
}
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
zhaoshu(0,0,1);
cout<<ans;
return 0;
}
注意一点,因为我们读入这一串数字的时候是从下标 1 1 1 开始的 , 所以一定要从 h e a d = 1 head=1 head=1 开始递归,否则会出现错误。
完结撒花~