蓝桥杯:拿糖果 记忆搜索解法(递归解法)

蓝桥杯:拿糖果 记忆搜索解法

问题描述

妈妈给小B买了N块糖!但是她不允许小B直接吃掉。
  假设当前有M块糖,小B每次可以拿P块糖,其中P是M的一个不大于根号下M的质因数。这时,妈妈就会在小B拿了P块糖以后再从糖堆里拿走P块糖。然后小B就可以接着拿糖。
  现在小B希望知道最多可以拿多少糖。
输入格式
  一个整数N
输出格式
  最多可以拿多少糖
样例输入

15

样例输出

6

数据规模和约定

N <= 100000

思路

这题DP的点比较明显:

假设当前有M块糖,小B每次可以拿P块糖,其中P是M的一个不大于根号下M的质因数。这时,妈妈就会在小B拿了P块糖以后再从糖堆里拿走P块糖。然后小B就可以接着拿糖。

状态定义与递推的推导:
假设现在从 j 块的堆中拿了 i 块,那么妈妈🐎也会拿 i 块,于是糖堆还剩下 j - 2 * i 块糖,在 j 块的糖堆中拿 i 块的最优解,就转变成 【在 j - 2 * i 的糖堆中的最优解 + i 】了

单次递归推导

  • 定义 dfs(x) 为求取在数量为 x 的糖堆中拿糖的最优解
  • 假设现在糖堆有 x 个糖,穷举 x 的所有质因数 z
  • 逐一计算 【dfs(x-2*z) + z】的值,取最大的,作为 dfs(x) 的解

递归边界条件

  • 如果是数量为负数的糖堆,拿不了,所以 return 0
  • 如果糖堆数量是 1,2,3这样的整数,他们没有质因数,拿不了,return 0

代码

#include <iostream>
#include <math.h>

using namespace std;

#define maxN 100009
int n;
int mem[maxN+1];	// 保存计算结果

// 判断素数
int is_prime(int x)
{
	if(x == 1)
	{
		return 0;
	}
	if(x == 2)
	{
		return 1;
	}
	for(int i=2; i<(int)sqrt(x); i++)
	{
		if(x%i == 0)
		{
			return 0;
		}
	}
	return 1;
}

// x是y的质因数吗?
int is(int x, int y)
{
	if(y%x==0 && x<=(int)sqrt(y))
	{
		if(is_prime(x))
		{
			return 1;
		}
	}
	return 0;
}

// 记忆搜索
int dfs(int x)
{
	if(x<=3)
	{
		return 0;
	}
	
	// 穷举x的所有质因数,即穷举所有拿法
	int max = 0;
	for(int i=2; i<=(int)sqrt(x); i++)
	{
		if(is(i, x))
		{
			int res;
			if(mem[x-2*i] != -1)
			{
				res = mem[x-2*i];
			}
			else
			{
				res  = dfs(x-2*i) + i;
			}
			
			if(res > max)
			{
				max = res;
			}
		}
	}
	
	mem[x] = max;
	return max;
}

int main()
{
	cin>>n;
	
	for(int j=0; j<=maxN; j++)
	{
		mem[j] = -1;
	}
	
	cout<<dfs(n)<<endl;
	
	return 0;
}

写了一个用数组DP的,没用递归的,但是后台运行错误,本地不会,等找到问题再放出来。。。。
即使是递归,时间也还算充分
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值