dfs
DFS深度优先搜索入门讲解——以洛谷P036选数问题为例
原始提问
大家好,这里是xsmb22,其实我也不会这些东西,但我想着还是要写一下。
在开始讲dfs之前,我想先问大家一个问题,大家有没有走过迷宫。应该不会有人没走过把,走迷宫你会怎么走呢,很显然,我们会在大脑中不撞南墙不回头地走迷宫,这就是dfs(深度优先便利的思想)的思想,同时由于迷宫总有撞墙的时候,我们就要走回头路了,在程序上的表现就是递归结束了。
话不多说,我们来一道简单的题目来讲讲。已知 n 个整数 x₁, x₂, …, xₙ,以及 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)。
第二行 n 个整数,分别为 x₁, x₂, …, xₙ(1≤xᵢ≤5×10⁶)。
输出格式
输出一个整数,表示种类数。
这是洛谷上一道基础的题目P036。
首先,我们可以写个函数或者欧拉筛来判断是否是素数。这道题比较简单,数据范围不大,我们用一个函数is_prime就可以。
bool is_prime(int num){
if(num <= 1)
return false;
if( x == 2 ){
return true;
}
for(int i = 2; i * i <= num; i++){
if(num % i == 0){
return true;
}
}
return false;
}
在此申明,由于我个人的命名习惯,我通常将数组命名为arr且常用1-based。
对于这道题目来讲,我们的暴力枚举需要知道什么量呢,显然,我们要在什么时候结束呢?显然,我们只要选完k个数算出他们的和就可以返回了,所以我们需要现在已经选了几个数的信息以及现在的和是多少用于判断和是否是质数来决定是否ans++。因此我们至少需要两个变量,一个变量cur用于记录现在已经选了几个数了,还有一个sum来记录现在的和。
另外,我们要选的是组合,现在我们先将k定死是2,你觉得你会这么枚举,显然,你不会选择(1,2)后又选择(2,1),对于k = 2的情况下,我们有类似于双指针的想法,先固定最左端的端点,再枚举右边的端点。这样不会重复了,k = 3, k = 4. k = 5…也是一样的因此,我们的完整代码就算是出来了:
cpp
#include <bits/stdc++.h>
#include <vector>
using namespace std;
typedef long long int ll;
int ans=0;
int n,k;
bool is_prime(int x){
if (x == 1)
return false;
if(x==2){
return true;
}
for (int i = 2; i * i <= x; i++)
if (x % i == 0)
{return false;}
return true;
}
void dfs(int cur,int sum,int start,int arr[]){
if(cur==k){
if(is_prime(sum)){
ans++;
}
return ;
}
for(int i=start; i<=n-k+cur+1; i++){
dfs(cur+1,sum+arr[i],i+1,arr);
}
return ;
}
int main(){
cin>>n>>k;
int arr[n+1];
for(int i=1;i<=n;i++){
cin>>arr[i];
}
dfs(0,0,1,arr);
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号