爬楼梯[C++/递归/递推/高精度]

本文分析了一道关于爬楼梯问题的编程挑战,涉及递归方法的优化,包括递推思想的应用和高精度数据处理。
摘要由CSDN通过智能技术生成

经典爬楼梯

题面如下:

数楼梯

题目描述

楼梯有 N N N 阶,上楼可以一步上一阶,也可以一步上二阶。

编一个程序,计算共有多少种不同的走法。

输入格式

一个数字,楼梯数。

输出格式

输出走的方式总数。

样例 #1

样例输入 #1
4
样例输出 #1
5

提示

  • 对于 60 % 60\% 60% 的数据, N ≤ 50 N \leq 50 N50
  • 对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 5000 1 \le N \leq 5000 1N5000

最近刷到递归专题,然后看到这个爬楼梯,当时想不就是经典的递归的应用嘛
于是马上写了一个简单的递归程序,体会这个代码就能对递归有进一步的理解

int ans;
void dfs(int u) {
	if (u == n)
		ans++;

	else if (u < n) {
		dfs(u + 1);
		dfs(u + 2);
	}


}

思路是这样子的:
深度优先搜索,
先找一种方法,看看能不能满足(刚好到第n层阶梯) 满足ans++
再找另一种方法
…到头为止

递归结束条件: 到头了
(u>=n)
上面代码的写法 else if()即没到头 那么此外的就是到头有关
然后特判了如果刚好到n层 即if(u==n) ans++
然后dfs 参数为void 函数执行完毕 无需手动return (当然也可以自行末尾加return)

当时我以为这样就结束了? 但是oj狠狠打脸
走楼梯"简单版"
原因是我超时了,为什么会超时,想了一会,超时应该是和栈有关,应该是爆栈了,
通俗的讲就是调用了太多的dfs()函数

既然爆栈了,那么我的第一想法就是掉头跑路,实施planB
之前没有系统刷过递推
但是这题我第一想到的就是递归转递推(我也不知道我什么思路)
好吧不打幌子
这里插入一个背景介绍(bushi):
上学期学计算机竞赛入门,老师讲递推(有时候提前给结论会比一个细节一个细节重复下去容易体会/换一个思路 上学期讲这个爬楼梯递推实现让我感觉摸不着头脑/也有可能是过了这么久学的东西变多了容易体会)

好吧,我已经忘记当时是怎么讲的了
但是这里这个思路可以先体会一下(我也不知道用的对不对)

我把它当作动态规划了 (既然是递推嘛,多多少少跟dp扯点关系)

废话不多说:
集合表示: f[i] :到第i层的方法数
属性: 数量
状态计算:
①最后一下走一步到第i层: f[i-1]
②最后一下走两步到第i层: f[i-2]

f[i]=f[i-1]+f[i-2];
初始化:
f[0]=1
(地面 只有一种方法 因为本来就在地面初始化成1 对后面从地面直接走两步到第2层有用!)
f[1]=1
(地面走一步到第一层)

然后写着写着发现 这不就是斐波那契数列…这么简单?!?

int n;
cin>>n;
f[0]=f[1]=1;
for(int i=2;i<=n;i++)
f[i]=f[i-1]+f[i-2];

然而
打脸++
难道是爆int了???
改成了 long long
还是爆了
打脸++

这时候挺无语的 因为我在刷递归,(好吧这题单名字叫做递推与递归)

只得了60分
(没看数据范围n上5000了 鬼知道到5000层阶梯有多少种方法)

直接看测试数据(bushi)(已经提交了 如果是oi根本没得看 IOI更没得看 当作学习可以看hhh)

n=500
输出:
225591516161936330872512695036072072046011324913758190588638866418474627738686883405015987052796968498626

太长了看不下去 不用想 高精度跑不掉了(python没烦恼,但是没好好学 从来没拿来用过 忘光光了)
只能背模板了…(bushi 根据思路来写 这样子才能应对)
本来都打算二维了 vector套vector 但是这样写不太行的样子 (弄了好久)
最后发现既然只和i-1和i-2有关
那么就滚动数组的思想吧(一开始也没想那么多 形象的写出来如下)
c=a+b;
a=b;
b=c;
自己看看体会 以后再细说(其实看懂这个也差不多理解了)

贴下代码: 高精度我就不讲了
具体参照高精度模板

#include <iostream>
#include <vector>
using namespace std;
int n, ans;
const int N = 50010;
typedef long long LL;


vector<int> add(vector<int> &A, vector<int> &B) {
	vector<int> res;
	int t = 0;
	for (int i = 0; i < A.size() || i < B.size() || t; i++) {
		if (i < A.size())
			t += A[i];
		if (i < B.size())
			t += B[i];
		res.push_back(t % 10);
		t /= 10;
	}
	return res;
}

int main(void) {
	cin >> n;
	vector<int> a, b, res;
	a.push_back(1), b.push_back(1);
  
	for (int i = 2; i <= n; i++)

	{
		res = add(a, b);
		a = b, b = res;
	}

	if (n == 1)
		puts("1");//因为是从2开始推的 n==1时侯res没有存东西(你也可以在前面自己改)
	else {

		for (int i = res.size() - 1; i >= 0; i--)
			cout << res[i];
		puts("");
	}


	return 0;

}

Ac了
又水一题… 但是要学会递推转递归/递归转递推 有时候会用上!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值