洛谷 P1036. 选数 -- dfs搜索
[NOIP2002 普及组] 选数
题目描述
已知 \(n\) 个整数 \(x_1,x_2,\cdots,x_n\),以及 \(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 \le n \le 20\),\(k<n\))。
第二行 \(n\) 个整数,分别为 \(x_1,x_2,\cdots,x_n\)(\(1 \le x_i \le 5\times 10^6\))。
输出格式
输出一个整数,表示种类数。
样例 #1
样例输入 #1
4 3
3 7 12 19
样例输出 #1
1
提示
【题目来源】
NOIP 2002 普及组第二题
这道题大概思路是想出来了 也想出了不降原则来去重 但还是没做出来 还是不够熟练
这道题有个关键点就是 不让选到的数重复 我们让dfs递归的时候循环从当前函数数的序号开始
比如 我们现在算数组中以第i个数开始的四个数的和能否是质数 那么接下来的一个数我们只能从i+1 i+2一直选到n 不能回头取选i前面的数
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int n, k, cnt;
int a[N];
bool is_prime(int x)
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )
{
if (x % i == 0) return false;
}
return true;
}
void dfs(int m, int sum, int startx) //m表示当前已经选择了几个数 sum表示当前选择数的和 startx表示当前选择数的序号 保证是升序序列 避免重复
{
if (m == k)
{
if (is_prime(sum)) cnt ++ ;
return;
}
else
{
for (int i = startx; i < n; i ++ ) //关键点!i从startx开始 保证是升序选取数组中元素 从而不会重复
{
dfs(m + 1, sum + a[i], i + 1); //这里升序起始值要变成i+1,以免算重
}
}
return;
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
dfs(0, 0, 0);
printf("%d\n", cnt);
return 0;
}
复习的时候发现这个dfs做法也行 就是两种选择 选或不选当前数
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int n, k, cnt;
int a[N];
bool is_prime(int x)
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )
{
if (x % i == 0) return false;
}
return true;
}
void dfs(int m, int sum, int startx) //m表示当前已经选择了几个数 sum表示当前选择数的和 startx表示当前选择数的序号 保证是升序序列 避免重复
{
if (startx > n) return; //搜出边界了直接返回
if (m == k)
{
if (is_prime(sum)) cnt ++ ;
return;
}
//两种选择
dfs(m, sum, startx + 1);
dfs(m + 1, sum + a[startx], startx + 1);
return;
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
dfs(0, 0, 0);
printf("%d\n", cnt);
return 0;
}
我的错误做法 只能看数组内连续的几个数是否是质数
比如选3个数就不能看第1个第3个第4个数加起来的情况
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int n, m, cnt, res;
int arr[N];
bool is_prime(int x)
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )
{
if (x % i == 0) return false;
}
return true;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &arr[i]);
for (int i = 1; i <= n; i ++ )
{
res = 0;
for (int j = i; j - i <= m -1 && j <= n; j ++ )
{
res += arr[j];
//cout << res << endl;
if (j - i == m - 1)
if (is_prime(res)) cnt ++ ;
}
}
printf("%d\n", cnt);
return 0;
}

浙公网安备 33010602011771号