洛谷------P1036 [NOIP2002 普及组] 选数

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷------P1036 [NOIP2002 普及组] 选数相关的知识,希望对你有一定的参考价值。

在这里插入图片描述
在这里插入图片描述

选数集体集合


回溯思想解题

思路:

这里是任选三个数相加,求所有和中的素数个数。

这里可以把问题转化一下,变为:求解出从n个数中任意选k个数构成的所有组合(组合不看元素之间的顺序,与排列区分开来),而我们这里只需要在找到一种组合时,计算当前组合的和,看是否等于素数,额外用一个变量sum,记录和为素数的个数,如果当前和为素数,那么sum++;

建议大家可以先看一下用回溯法求解组合问题,再回头来看此题,会发现其实很简单:

leetcode 39. 组合总和—回溯篇2
leetcode 40. 组合总和 II—回溯篇3

图解:
在这里插入图片描述
其实从上图中,我们就可以看出存在能够优化的地方:
在这里插入图片描述
那么如何判断当前元素到达末尾的元素个数够不够组成k个呢?

这里我们首先获取当前的结果数组中的元素个数size,用k-size来获得当前剩余需要的元素个数num,然后用可选数组的大小减去index获得当前最多可以选择的数字,然后与num进行比较 ,如果比num小,说明不满足条件,结束当前循环

代码;

#include<iostream>
using namespace std;
#include<bits/stdc++.h>
class Solution {
	vector<int> num;
	int sum = 0;
	//判断一个数是否为质数
	bool isPrime(int num)
	{
		if (num <= 3) {
			return num > 1;
		}
		// 不在6的倍数两侧的一定不是质数
		if (num % 6 != 1 && num % 6 != 5) {
			return false;
		}
		int Sqrt =sqrt(num);
		for (int i = 5; i <= Sqrt; i += 6) {
			if (num % i == 0 || num % (i + 2) == 0) {
				return false;
			}
		}
		return true;
	}
public:
	int solution(vector<int>& v,int k,int index)
	{
		if (k==0)
			return  isPrime(accumulate(num.begin(), num.end(), 0))?++sum:sum;
		int nums = k - num.size();//剩余需要选择的数字个数
		int selNum = v.size() - index-1;//当前剩余最多可选的数字个数
		for (int i = index; i < v.size()&&selNum>=nums; i++)
		{
			num.push_back(v[i]);
			solution(v, k-1, i + 1);
			num.pop_back();
		}
		return sum;
	}
};
int main()
{
	Solution s;
	vector<int> v;
	int n, k;
	cin >> n >> k;
	for (int i = 0; i < n; i++)
	{
		int val;
		cin >> val;
		v.push_back(val);
	}
	cout << s.solution(v, k, 0) << endl;
	return 0;
}

在这里插入图片描述

以上是关于洛谷------P1036 [NOIP2002 普及组] 选数的主要内容,如果未能解决你的问题,请参考以下文章

[NOIP2002] 提高组 洛谷P1034 矩形覆盖

[NOIP2002] 提高组 洛谷P1033 自由落体

[NOIP2002] 提高组 洛谷P1031 均分纸牌

DFS-选数

DFS-选数

DFS-选数