【GZOJ】1369——小明跳楼梯

跳楼梯问题与斐波那契数列
本文探讨了一个经典的编程问题——跳楼梯的不同方式数量,并通过观察规律及递推公式的方式,揭示了该问题与斐波那契数列之间的联系。文中还提供了一段C++代码作为实现示例。

题目链接广大OJ1369
本题亦为广大15级第一次周赛的B题。

题目内容

Problem Description
小明很喜欢跳楼梯。
他可以一次跳一阶楼梯(记为1),也可以一次跳两个台阶(记为2)。
那么问题来了。小明跳三个台阶共有几种方法?
答案很简单,一共三种。
分别是:111,12,21。
换成语言描述就是:连跳三阶楼梯,跳一阶后再一次跳两个台阶,一次跳两个台阶后再跳一阶,共三种。
以此类推,小明跳四个台阶就一共有五种,分别是:1111,112,121,211,22。
那么问题来了。小明跳n阶台阶共有几种方法?

Input
有多组输入数据。

每组数据共一行,为一个整数n(1<=n<=70)

Output
对于每组输入数据,输出一个整数m,m为小明跳n阶楼梯的方法数。
Sample Input
1
2
4
Sample Output
1
2
5
Hint
于是小明就孤独一生了。

可喜可贺可喜可贺。

解题思路

本题有两种方法:

1.观察规律。小明跳一阶楼梯有1种方法,跳两阶楼梯有2种方法,跳三阶楼梯有3种方法,跳四阶楼梯有5种方法,依次类推,接下去的方法数为8,13,21,34,。。。。。。。
不难发现这是一个斐波那契数列,于是就可以直接按求斐波那契数列的公式来算。

2.求递推公式。利用状态转移的思想。假设小明跳n阶楼梯会有F[n]种方法,那么小明跳这n阶楼梯的所有方法可以分为两类:
一,最后一步为跳一阶的方法
二,最后一步为跳两阶的方法
最后一步为跳一阶的方法除去最后一步就是跳n-1阶楼梯的方法数,最后一步为跳两阶的方法除去最后一步就是跳n-2阶楼梯的方法数。
所以便可以得到如下递推式:
F[n]=F[n-1]+F[n-2]
然后把特殊情况列出来(因为上式对n=1和n=2的情况不适用),于是就可以在算这道式子之前先初始化F[1]为1,F[2]为2。(当然也可以初始化F[0]=1,F[1]=1)
最后你会发现,这个推出来就是斐波那契数列的递推式。

代码

#include<cstdio> 
int n;
long long a[80];
int main()
{
    a[1]=1;
    a[2]=2;
    for(int i=3;i<=70;i++)
        a[i]=a[i-1]+a[i-2];
    while(scanf("%d",&n)==1)
        printf("%lld\n",a[n]);
    return 0;
}
### 小明爬楼题的算 小明爬楼题通常是指给定一个楼有 `n` 个台阶,每次可以爬 `1` 步、`2` 步甚至更多步(例如 `1`、`2`、`3` 步),计算有多少种不同的走可以到达楼顶部。这类题通常可以通过递归、动态规划(Dynamic Programming, DP)或数学公式来解决。 #### 递归解 递归解是基于题的定义直接推导出的。假设 `f(n)` 表示到达第 `n` 级台阶的走总数,那么可以得到递推关系: - `f(n) = f(n-1) + f(n-2) + f(n-3)` (如果每次可以爬 `1`、`2`、`3` 步)。 这种方的时间复杂度较高,为指数级 $ O(3^n) $,因为存在大量的重复计算。 #### 动态规划解 为了避免递归中的重复计算,可以使用动态规划来优化。动态规划的核心思想是通过存储中间结果来避免重复计算。 例如,对于 `n` 级台阶,可以使用一个数组 `dp` 来存储每一步的结果: - 初始化 `dp[0] = 1`,`dp[1] = 1`,`dp[2] = 2`。 - 递推公式为 `dp[i] = dp[i-1] + dp[i-2] + dp[i-3]`。 这种方的时间复杂度为 $ O(n) $,空间复杂度也为 $ O(n) $。 #### 非递归解 非递归解进一步优化了空间复杂度,只需要常数级的空间来存储中间结果。例如,可以使用三个变量 `a`、`b`、`c` 来分别表示 `dp[i-3]`、`dp[i-2]`、`dp[i-1]`,并逐步计算当前值。 例如,对于 `n` 级台阶: ```python def count_ways(n): if n == 0: return 1 if n == 1: return 1 if n == 2: return 2 a, b, c = 1, 1, 2 for _ in range(3, n + 1): total = a + b + c a, b, c = b, c, total return c ``` 这种方的时间复杂度为 $ O(n) $,空间复杂度为 $ O(1) $。 #### 数学公式解 在某些特定情况下,可以直接利用数学公式来计算结果,而不需要循环或递归。例如,斐波那契数列可以通过公式直接计算,但需要注意浮点数精度题。 #### 特殊情况处理 当某些台阶不可通过时(例如第 `60` 级台阶是坏的),可以在动态规划中进行特殊处理。在计算过程中,如果遇到不可通过的台阶,则直接过该台阶的计算。 例如,可以使用以下方处理不可通过的台阶: ```python def count_ways_with_broken(n, broken_step): if n == 0: return 1 if n < broken_step: return count_ways(n) # 使用动态规划处理 dp = [0] * (n + 1) dp[0] = 1 dp[1] = 1 dp[2] = 2 for i in range(3, n + 1): if i == broken_step: dp[i] = 0 else: dp[i] = dp[i-1] + dp[i-2] + dp[i-3] return dp[n] ``` 这种方的时间复杂度和空间复杂度与动态规划相同。 #### 时间复杂度和空间复杂度分析 - **递归解**:时间复杂度为 $ O(3^n) $,空间复杂度为 $ O(n) $(由于递归栈)。 - **动态规划解**:时间复杂度为 $ O(n) $,空间复杂度为 $ O(n) $。 - **非递归解**:时间复杂度为 $ O(n) $,空间复杂度为 $ O(1) $。 - **数学公式解**:时间复杂度为 $ O(1) $,空间复杂度为 $ O(1) $。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值