题解:P1036 [NOIP 2002 普及组] 选数
前置知识
你需要先学习深度优先搜索和基础语法,阅读本篇题解前请确保你已经掌握上述内容。
思路讲解
题目要求我们从给出的
搜索函数要定义三个参数,分别表示当前已选择几个元素、上个元素的下标、当前选的数字之和,记录已选几个元素的参数用于判定边界及时退出,上个元素的下标参数用于剪枝优化,同时也防止了两个数顺序不同导致的重复计算,当前选的数字之和参数用于记录数字和,在末尾判断是否为素数时能够起到优化作用,防止多次循环求和导致的超时。
每次搜索时判定是否已选够
代码展示
写的时候注意搜索函数的编写,保证基本框架正确的同时,也要记得把上述的剪枝优化写进去。如果你的程序输出比标准答案要大,可以检查一下是否重复选相同元素,顺序不同的情况是否重复计算。
写的时候注意细节,下面是我的代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,cnt; // 题面里的n和k,以及累加方案数的变量cnt
int a[21]; // 存储n个整数
void dfs(int w,int start,int sum){ // 已选个数、上个元素下标、数字和
if (w == m){ // 判断边界,是否已选k个数
bool y=1; // 假设是素数
for(int i=2;i<=sqrt(sum);i++){ // 枚举可能的因数来判断素数
if(sum%i==0){ // 如果可以整除
y=0; // 那就不是素数,标记
break; // 退出循环
}
}
if(y) cnt++; // 如果是素数就累加方案数
return; // 返回上一层搜索调用
}
for(int i=start+1;i<n;i++){ // 枚举,注意从上个元素下标的下一个位置开始选,防止重复和多次计算
dfs(w+1,i,sum+a[i]); // 选的数字个数加一,把上个元素下标设为该元素下标,数字和要加上这个元素的值
}
}
int main(){
cin >> n >> m; // 读入n和k,我只是改了变量名,含义是一样的
for(int i=0;i<n;i++) cin>>a[i]; // 读入n个整数
dfs(0,-1,0); // 调用函数,注意传参的已选个数、上个元素下标、数字和,还没选所以是0个数字,下标在搜索时会加一处理,所以设为-1,没选数字所以和为0
cout << cnt; // 输出方案数
return 0; // 完结撒花
}