P1036 [NOIP2002 普及组] 选数 (DFS)

传送门:P1036 [NOIP2002 普及组] 选数

题目描述:

已知 nnn 个整数 x1,x2,⋯ ,xn,以及 1 个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4 个整数分别为 3,7,12,19时,可得全部的组合与它们的和为:
3+7+19=29
7+12+19=38
3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29。

输入格式

第一行两个空格隔开的整数 n,k(1≤n≤20,k<n)。
第二行 n 个整数,分别为 x1,x2,⋯ ,xn(1≤xi≤5×106)。

输出格式

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

思路

不降原则

因为是求种类数 ,所以需要去重,有点麻烦,所以就按照从大到小的顺序全排列

例如,在1 2 3 4,四个数字中选三个数字
1 2 3
1 2 4
2 3 4
因为123跟213,231,312…虽然顺序不同,但是本体是求和,他们的和都相等,是重复的结果

所以,从大到小输出,避免重复

具体实现,看下列代码,dfs函数的参数y,就代表当前选择的数字在全部数字中的位置是第y个,
for循环也是从第y个开始,省去了循环的时间,而且也在避免重复
之后dfs递归y+1,自动选择比它大的数字进行排序

void dfs(int x, int s, int y) {
	if (x == k && primer(s)) {
		cnt++;
		return ;
	}
	
	if (x >= k) return; 
	for(int i = y; i < n; i++) {
		if (!book[i]) {
			dfs(x + 1, s + a[i], i + 1);

		}
	}
}

代码详情

#include<stdio.h>
#include<string.h>
#include<math.h>
//普通方法现在我有点写不出来,只能学dalao的不降原则 
int a[30], n, k, cnt;
//int book[30];不用标记了,直接按大小选数字

//函数,判断是否是素数
int prime(int t) {
	int p = sqrt(t);
	if(t == 1)return 0;
	for(int i = 2; i <= p; i++) {
		if (t % i == 0)return 0;
	}
	return 1;
}
//x 现在是第几个数
//s 现在x个数的和
//y 选的第x个数 在所有的数中排第几
void dfs(int x, int s, int y) {
	if (x == k && primer(s)) {
		cnt++;
		return ;
	}
	
	if (x >= k) return; 
	for(int i = y; i < n; i++) {
		if (!book[i]) {
//			book[i] = 1;
//			s += a[i];
//			if (x == k && primer(s)) cnt++;
			dfs(x + 1, s + a[i], i + 1);
//			s -= a[i];
//			book[i] = 0;
		}
	}
//	dfs(x+1, s);
}

int main() {
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; i++) {
		scanf("%d", &a[i]);
	}
	dfs(0, 0, 0);
	printf("%d", cnt);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值