课程29_17 1125 爬楼梯
题目:
题目描述:
楼梯有n级台阶,上楼可以一步上1级,也可以一步上2级,计算有多少种不同的走法
其中n<=35
输入描述:
一个正整数n,占一行
输出描述:
一个整数,占一行,问题的结果,数据保证输出在32位有符号整型数据范围内。
样例输入:
20
33
样例输出:
10946
5702887
解析:
非常经典的子问题题目。
何为子问题问题(听起来有些拗口)呢?如果某一个问题可以分解为确定个数个更小的问题的话,这就是一个子问题问题。对于这种问题,我们直接把它分解为若干个更小的问题,并且去解决这些更小的问题(同时这些更小的问题也有可能还可以分成更更小的问题),直到这些小问题都小到足够简单去解决,我们就得到了想要知道的答案。而这些小问题,就是我们常说的子问题。
如果想用递归的方式做这种问题,我们需要注意几个要点:
- 一个问题被分解后的小问题和它本身是不是同一个类型的?
举个例子,求定积分,我们会先求它的原函数,然后再分别把积分起点和终点带入并相减,这个求原函数其实就是被分解出去的一个小问题,但是很明显求原函数和求定积分不是一个类型的问题,那么很明显就不符合这个条件。
但是如果是求斐波纳挈数列(1、1、2、3、5,每一项等于前两项和),我们要求第n项,可以把它拆分为求第n-1和第n-2项,而求第n-1项和求第n项是同一个类型的问题,就可以用。 - 这个子问题,是否可以在足够小的时候简单到可以做出来?
这个挺重要,但是也挺不重要的。重要的在于:如果问题分割的再小,还是难以解决,那么就不能用这个方法。而不重要的在于:绝大部分的这类问题都满足这个条件。比如斐波纳挈数列,在n=1、2的时候值为1,这就是“足够简单到可以做出来”。而这类问题大部分在数字很小的时候是可以靠人脑计算出来的。
回到题目当中。我们要求的是,每次走1步或者2步,走到第n台阶需要多少步。
首先如果我们距离第n台阶只差1步,或者只差2步,那么我们都可以“一次”到达第n台阶。
那么这个子问题就迎刃而解了,既然在第n-1台阶和在第n-2台阶都只需要一次就可以到达终点,那么到达第n台阶的方法数自然就是n-1台阶的方法加上n-2台阶的方法了。这个数列刚好是斐波纳挈数列的变型,其中f(0)=0,f(1)=1,f(2)=2,后面符合斐波纳挈数列的规则。
解题:
题目已经告诉我们n小于35,那么我们开一个数组来存储值,求到哪存到哪。比如如果之前求过f(9),那么9以下的肯定都求过了,这个时候如果又要求4,我们就可以直接输出,这样可以避免一个数据被反复算了很多次。
以下代码计算完了0~32768的所有情况,因为这道题原来的数据范围是n<=32768,而如果不把已经算过的内容存起来,是绝对会TLE的。32768的范围其实本来就有点危险,所以后来题目改成了35,大家可以按照自己的需求去修改代码。
参考代码:
// TSOJ-1125 爬楼梯
#include <iostream>
using namespace std;
int r[32768] = {0};
long long int result(int n)
{
if(r[n]!=0)
return r[n];
return result(n-1)+result(n-2);
}
int main()
{
r[0]=0;
r[1]=1;
r[2]=2;
int ns;
while(cin>>ns)
{
cout<<result(ns)<<endl;
}
return 0;
}