Bootstrap

【DFS】深度优先搜索 洛谷选数例题讲解

DFS 深搜 选数问题

[NOIP2002 普及组] 选数

题目描述

已知 n n n 个整数 x 1 , x 2 , ⋯   , x n x_1,x_2,\cdots,x_n x1,x2,,xn,以及 1 1 1 个整数 k k k k < n k<n k<n)。从 n n n 个整数中任选 k k k 个整数相加,可分别得到一系列的和。例如当 n = 4 n=4 n=4 k = 3 k=3 k=3 4 4 4 个整数分别为 3 , 7 , 12 , 19 3,7,12,19 3,7,12,19 时,可得全部的组合与它们的和为:

3 + 7 + 12 = 22 3+7+12=22 3+7+12=22

3 + 7 + 19 = 29 3+7+19=29 3+7+19=29

7 + 12 + 19 = 38 7+12+19=38 7+12+19=38

3 + 12 + 19 = 34 3+12+19=34 3+12+19=34

现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数: 3 + 7 + 19 = 29 3+7+19=29 3+7+19=29

输入格式

第一行两个空格隔开的整数 n , k n,k n,k 1 ≤ n ≤ 20 1 \le n \le 20 1n20 k < n k<n k<n)。

第二行 n n n 个整数,分别为 x 1 , x 2 , ⋯   , x n x_1,x_2,\cdots,x_n x1,x2,,xn 1 ≤ x i ≤ 5 × 1 0 6 1 \le x_i \le 5\times 10^6 1xi5×106)。

输出格式

输出一个整数,表示种类数。

样例 #1

样例输入 #1

4 3
3 7 12 19

样例输出 #1

1

提示

【题目来源】

NOIP 2002 普及组第二题

代码与解析

  • 这个题与其他DFS相比,最大的问题是如何找出所有不重复的情况
  • 从最特殊的角度看,我们可以发现,4个数中任选3个,那所有情况中,就可使后一个数大于前一个数,且每一种情况都有一个数不选,就组成了这四种情况。
  • 比如 7 8 5 6这四个数
>  -             5     6     7
>  - 		     6     7     8
>  -             5     7     8
>  -             5     6     8
  • 用DFS写的话,可以再加一个参数来维护,使得每次搜索时,后一个数总要比前一个数字大。
  • 具体这样操作👇代码里有注释
#include<bits/stdc++.h>
#define IOS std::ios::sync_with_stdio(false),cout.tie(0),cin.tie(0);//加快输入输出
using namespace std;
const int N = 1e6;
int n,m,arr[N],arr2[N],num[N],zhishu = 0,maxn = 0;
bool vis[N];//标记数组

void check(int x)//检验质数函数
{
	int suc = 1;//标记初始为真
	if(x != 1)
	{
		for(int i = 2;i <= x/i;i++)//筛质数,筛到一半,即i^2 = x,i <= 根号x
		{
			if(x % i == 0)//判断是否是x的因数
			{
				suc = 0;//标为假
				break;
			}
		}
	}
	if(suc == 1)	zhishu++;//质数数量累加
	if(suc == 0)	return ;
}


void dfs(int now,int sum,int maxn)//深搜
{	
	arr[sum] = now;//当前搜索的数存到临时数组
	if(sum == m)//判断边界
	{
		int a = 0;
		for(int i = 1;i <= m;i++)	a += arr[i];//求和
		check(a);//检验质数
	}
	for(int i = sum+1;i <= n;i++)//从更深一层开始循环
	{
		if(i > maxn)//当后一个数比前一个大时
		{
			dfs(arr2[i],sum+1,max(maxn,i));//从更深的一层搜索,维护较大的一个数
		}
	}
}



int main()
{
	IOS;//加快输入输出
	cin>>n>>m;//读入n,m
	for(int i = 1;i <= n;i++)	cin>>arr2[i];//n个数存到数组里
	for(int i = 1;i <= n;i++)
	{
		dfs(arr2[i],1,max(maxn,i));//开始搜索
	}
	cout<<zhishu;//输出质数个数
	
}
  • 本题对于初学者稍有难度,但可以参考其他入门的DFS题目,熟悉了基本模板,无论写起来还是理解起来都会更加简便
  • 对于初次学习dfs和bfs的同学一定不要急,将代码自己多写几遍,没事就看看,慢慢就理解了😊
;