数的计算(递推 / 递归)

原题链接

题意

我们要求找出具有下列性质数的个数(包含输入的正整数 n)。

先输入一个正整数 n(n≤1000),然后对此正整数按照如下方法进行处理:

1.不作任何处理;

2.在它的左边加上一个正整数,但该正整数不能超过原数的一半;

3.加上数后,继续按此规则进行处理,直到不能再加正整数为止。
输入n, 输出一个整数(该整数我在代码中用re[n]来表示)表示具有该性质的数的个数;

(例如 6 左边加一个不大于 6 的一半的数 2 变为 26 , 2 的左边还可以加不大于 2 的一半的数 1,变为 126)

案例
输入 6
输出 6

案例中的 6 个数是 6,16,26,126,36,136

解析

这道题可以直接递归, 也可以找到它的递推式来做.

一 递推解法

利用递推求解首先就是要找到这道题的递推式;
当我看懂题意后, 我首先罗列了从 1 开始的多个整数在进行操作后输出的结果 re[i], 最终发现了这道题的递推公式就是 re[n] = 1 + re[1] + re[2] + re[3] + …+ re[n/2]; 并且初始条件 re[1] = 1; 找到了递推公式, 知道了初始条件我们就可以用这个递推公式来做这道题了
以下是我利用该递推式写的代码:

#include <bits/stdc++.h>//递推法求解; 
using namespace std;
int re[10005], n, ans;
int main() {
	cin >> n;
	ans = 1;//即递推re[n]的递推公式开头的数字 1;
	for (int i = 1; i <= n / 2; i++) {//将re[1] 到 re[n/2]相加求re[n] 的结果;
		re[i] = 1;//对于re[1]到re[n/2]利用递推公式, 先赋值为公式开头的 1;
		for (int j = 1; j <= i / 2; j++) {//求 1 到 n/2 每个数的r[i];
			re[i] += re[j];
		}
		ans += re[i]; 
	}
	cout << ans << endl;
	return 0;
} 
二 递归解法

这道题还可以利用递归来计算, 但如果单纯的用递归进行回溯,在这道题上就会卡时间(事实上我这样做就是TLE了), 所以又学习了一下, 知道了这里用到了 记忆化搜索 的思想;
就是你要用一个数组来记录你之前已经遍历过的情况, 再次遇到这种情况就不用再次调用函数再算一遍了, 直接把数组中记录这种情况的数输出就行了, 这样就避免了做过多的无用功, 提高了递归的效率;
那么这道题的递归做法就可以用上这种思想了, 下面就是我写的代码了:

#include <bits/stdc++.h>//递归法求解; 
using namespace std;
int re[10005], n, ans; 
int search(int x) {//; 
	int temp = 1;//temp我用来代表该次函数运行中 x 的 re[x]当然可以去掉它,直接用re[x]表示也行; 
	if (re[x] != -1) {
	//若re[x] != 0, 就说明 re[x]在之前的函数调用中已经被计算出了, 此时直接返回 r[x]就可以;
		return re[x]; 
	}
	for (int i = 1; i <= x / 2; i++) {
		temp += search(i);
	}
	return re[x] = temp;
}
int main() {
	cin >> n;
	memset(re, -1, sizeof(int) * (n + 1));
	//memset 一般用来把数组初始化为0或-1, 这里将re数组初始化为 -1, 说明它还未记录数据;
	re[1] = 1;//初始条件;
	cout << search(n);
	return 0;
}
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值