问题描述
生物学家小 R 正在研究一种特殊的兔子品种的繁殖模式。这种兔子的繁殖遵循以下规律:
- 每对成年兔子每个月会生育一对新的小兔子(一雌一雄)。
- 新生的小兔子需要一个月成长,到第二个月才能开始繁殖。
- 兔子永远不会死亡。
小 R 从一对新生的小兔子开始观察。他想知道在第
A个月末,总共会有多少对兔子。请你帮助小 R 编写一个程序,计算在给定的月份
A时,兔子群体的总对数。注意:
- 初始时有 1 对新生小兔子。
- 第 1 个月末有 1 对兔子:原来那对变成了成年兔子,并开始繁殖。
- 第 2 个月末有 2 对兔子:原来那 1 对成年兔子,繁殖了 1 对新生的小兔子。
- 从第 3 个月开始,兔子群体会按照上述规律增长。
题目分析
这是一道数学问题,而且是很经典的斐波拉契数列(又称兔子数列),这道题也是一道很经典的递归算法题(但本题如果用递归会运行超时,所以要使用动态规划)。
现在我们来假设分析一下:
第1个月末有1对兔子,此时兔子已经成熟,下个月就能开始繁殖。
第2个月末有2对兔子,因为上个月剩下的兔子开始繁殖,所以兔子总数变为了1+1对。
第3个月末有3对兔子,因为上个月出生的兔子到了本月才成熟,所以只繁殖了1对兔子,兔子总数为2+1对
第4个月末有5对兔子,因为初始的兔子和第二个月出生的兔子都可以繁殖,所以繁殖了2对兔子,同时第3个月出生的兔子也成熟了。此时兔子总数为3+2对。
第5个月末有8对兔子,因为初始的兔子和第二个月和第三个月出生的兔子都可以繁殖,所以繁殖了3对兔子,同时第4个月出生的兔子也成熟了。此时兔子总数为5+3对。
通过对上述案例分析可得,数列按照{1,1,2,3,5,8...}的顺序排列,我们也可以看出规律。从第3个月开始,这个月的兔子数量等于前两个月的兔子数之和
代码
def solution(A):
f = [0] * (A + 1) # 创建一个大小为 A + 1 的数组
f[0] = f[1] = 1 # 基础情况,f(0) 和 f(1) 都为 1
for i in range(2, A + 1):
f[i] = f[i - 1] + f[i - 2] # 动态规划状态转移
return f[A] # 返回第 A 个斐波那契数
我们先创造一个数组用来记录各个月的兔子数量,这样做可以避免重复计算某一月份的兔子数量,从而解决超时问题。
如果本题使用递归算法,我们需要不停地重复计算某一月份的兔子数量。
例如:f(5)=f(4)+f(3)
这时我们需要计算 f(3)=f(2)+f(1) 和 f(4)=f(3)+f(2)
为了计算f(4),我们需要重新计算一遍f(3)
所以当月份很大时,我们会发现会出现重复计算了很多月份,这样子的操作会导致运行超时,所以我们就需要用到动态规划。