洛谷P1306

本题的核心是求解数组合,因为此题比较简单可以使用两层for循环暴力求解,也可以使用回溯+递归进行求解,本人选择的是第二种。

递归:将未知的问题缩小,知道访问到已知问题,便开始返回数值,知道解决未知的问题。

组合数本质上是二叉树。

假设我们要在{1,2,3,4,5}中任取3个进行组合,则有

因为我们仅仅是求组合,而不需要排列,又因为组合中的数是无序且不重复的,所以取过的 元素便不能再取避免重复。

而每个数都有取和不取两种结果,而回溯法就是模拟上图路径。

接下来上代码

#include <bits/stdc++.h>

using namespace std;
const int N = 30;
int x[N];
int n, k, p, ans;

int isprime(int m)//判断素数
{
	for (int i = 2; i*i <= m; ++i)
	{
		if (m % i == 0)
			return 0;
	}
	return 1;
}

void dfs(int q, int num, int sum)
{
	//q是我们要确定第q个数是否需要选
	//num是确定我们一共选了多少个数
	//sum是确定我们取的数的总和
	if (q > n)//终止条件:是否所有数都选过了,即是否达到了树的叶子结点
	{
		if (num == k)//判断选的数是否够了要求的数
		{
			ans += isprime(sum);//判断素数并且相加
		}
		return;
	}
	dfs(q + 1, num + 1, sum + x[q]);//搜索q并且把q纳入其中一个组合数的集合中
	dfs(q + 1, num, sum);//搜索q但是没有选择把q纳入其中一个组合数的集合中
}


int main()
{
	ans = 0;
	cin >> n >> k;
	for (int i = 1; i <= n; ++i)
		cin >> x[i];
	dfs(1, 0, 0);//从1开始进行组合
	cout << ans << endl;
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值