[C++]洛谷 选数&&数的划分 dfs方法详解

-P1036 [NOIP2002 普及组] 选数-

[输入样例]

4 3
3 7 12 19

[输出样例]

1

[解题思路]

给我们n个数,让我们任选其中k个数并求和,求使这个和为素数的组合共有多少种。对于这种多选多的模型,我们可以用dfs的方法递归求出符合条件的总数。

需要注意的是,如果两次选取的数相同,则他们的和也相同,这应该认为是同一种情况,因此,我们必须要想一个办法,保证递归过程中无重复的选取组合。

具体实现方式如下:我们枚举第一次选取的数,接下来选取的每个数都满足在数组中的位置大于前一个数,这样,我们就能不重复地完成所有组合的遍历。

接下来就是代码部分:

#include<vector>
#include<iostream>
using namespace std;

//判断是否为素数
bool isPrime(int n)
{
	bool ret = true;
	for (int i = 2; i * i <= n; i++)
	{
		if (n % i == 0)
		{
			ret = false;
			break;
		}
	}
	return ret;
}

//传入参数:数组arr、还需继续选取个数k、所选定的数之和sum(缺省值为0)、开始搜索下一个数的起始位置pos(缺省值为0)
int dfs(vector<int> arr, int k, int sum = 0, int pos = 0)
{
	//如果无需继续选取数,则判断总和是否为素数,直接返回isPrime的结果
	if (k == 0)
	{
		return isPrime(sum);
	}

	//若k>0,则继续选取下一个数
	int ret = 0;
	for (int i = pos; i < arr.size(); i++)
	{
		//调用递归选取下一个数时需要改变的参数:还需继续选取的个数k减去1,sum加上选取的这个数的值,下一次搜索的起始位置为本次搜索的位置+1
		ret += dfs(arr, k - 1, sum + arr[i], i + 1);
	}
	return ret;
}

int main()
{
	//参数读取及arr的声明和初始化
	int n, k;
	cin >> n >> k;
	vector<int> arr;
	while (n--)
	{
		int t;
		cin >> t;
		arr.push_back(t);
	}

	//调用dfs并打印
	cout << dfs(arr, k);
	return 0;
}

接下来,我们来看一道可以用类似解法解出的题目。

-P1025 [NOIP2001 提高组] 数的划分-

[输入样例]

7 3

[输出样例]

4

[详解]

#include<iostream>
using namespace std;

//传入参数:需要分割的数num,剩余需要分割的数目k,上一次分割出的数
int dfs(int num, int k, int pre_part = 1)
{
	//若需要分割的数目为1,则说明该分割方式有效,返回1
	if (k == 1) return 1;

	//若num小于需要分割的个数,则说明该方案不可行,返回0
	if (num < k) return 0;

	//若还能继续分割,进行递归计算有效分割个数
	int ret = 0;
	//这里解释一下为什么从pre_part开始枚举:由于1,1,5、1,5,1、5,1,1属于同一种分割,
    //为了避免分割方式重复,我们只要保证每一次后分割出的数大于等于前一次分割出的数即可
	//同时,由于我们分割出的数满足非严格递增,我们枚举第一次分割出的数一定小于等于num/2
	for (int i = pre_part; i <= num / 2; i++)
	{
		ret += dfs(num - i, k - 1, i);
	}
	return ret;
}

int main()
{
	int num, k;
	cin >> num >> k;
	cout << dfs(num, k, 1);
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值