动态规划在兔子繁殖问题中的应用
这个问题本质上是一个斐波那契数列的变种,规律如下:
- 第 1 个月末:1 对兔子。
- 第 2 个月末:2 对兔子。
- 从第 3 个月开始:总兔子数 = 上个月的总兔子数 + 上上个月的总兔子数。
动态规划的核心思想是将复杂问题分解为子问题,通过记录中间状态避免重复计算,降低时间复杂度。
问题分析与解法梳理
-
状态定义
用dp[i]表示第i个月末兔子的总对数。 -
状态转移方程
根据题目规律:dp[i]=dp[i−1]+dp[i−2]dp[i] = dp[i-1] + dp[i-2]dp[i]=dp[i−1]+dp[i−2]
解释:
- dp[i−1]dp[i-1]dp[i−1]:上个月的兔子总数(保留原有的成年兔子)。
- dp[i−2]dp[i-2]dp[i−2]:上上个月的成年兔子,繁殖出的小兔子数。
-
初始条件
- dp[1]=1dp[1] = 1dp[1]=1:第 1 个月末有 1 对兔子。
- dp[2]=2dp[2] = 2dp[2]=2:第 2 个月末有 2 对兔子。
-
结果表达式
返回 dp[A],即第 A 个月末兔子的总对数。
动态规划代码实现
以下是 Python 实现:
def rabbit_population(A):
# 初始条件
if A == 1:
return 1
if A == 2:
return 2
# 动态规划数组
dp = [0] * (A + 1)
dp[1], dp[2] = 1, 2
# 状态转移
for i in range(3, A + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[A]
# 测试用例
print(rabbit_population(1)) # 输出: 1
print(rabbit_population(5)) # 输出: 8
print(rabbit_population(15)) # 输出: 987
优化版本(滚动数组)
由于动态规划只依赖最近两个状态值,可以通过滚动数组优化空间复杂度,从 O(A)O(A)O(A) 降为 O(1)O(1)O(1):
def rabbit_population(A):
if A == 1:
return 1
if A == 2:
return 2
prev, curr = 1, 2
for _ in range(3, A + 1):
prev, curr = curr, prev + curr
return curr
# 测试用例
print(rabbit_population(1)) # 输出: 1
print(rabbit_population(5)) # 输出: 8
print(rabbit_population(15)) # 输出: 987
对入门同学的学习建议
-
理解问题本质
这类问题的核心在于识别递推关系,结合动态规划的思想,通过保存中间结果避免重复计算。 -
明确动态规划四要素
- 状态定义
- 状态转移方程
- 初始条件
- 最终结果表达式
-
学习空间优化
动态规划初学者往往直接创建数组存储所有状态,但对于类似斐波那契数列的问题,可以通过变量滚动降低空间复杂度。 -
举例验证递推
在手动验证 dp[i]dp[i]dp[i] 的变化规律时,多画图、多代入几组小规模数据。
总结
这道题是动态规划的经典入门问题。通过对状态转移方程的推导,逐步掌握递推公式和优化技巧,可以为日后更复杂的动态规划问题打下扎实基础。