动态规划(Dynamic Programming, DP)是一种解决复杂问题的算法,它通过将问题分解成较小的子问题,并利用这些子问题的解来有效解决整个问题。动态规划特别适用于具有重叠子问题和最优子结构的问题。
案例分析:斐波那契数列
斐波那契数列是动态规划常见的入门示例,其中每个数字是前两个数字的和。问题可以描述为:给定一个整数 𝑛n,计算斐波那契数列的第 𝑛n 项。
递归方法
一种简单的实现是使用递归,但这种方法效率低下,因为它重复计算了许多子问题。
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
# 测试
print(fibonacci(10)) # 输出第10项斐波那契数
动态规划方法
动态规划通过存储先前计算的结果来避免重复计算,显著提高效率。
自顶向下的带备忘录的递归方法:
def fibonacci_memo(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fibonacci_memo(n-1, memo) + fibonacci_memo(n-2, memo)
return memo[n]
# 测试
print(fibonacci_memo(10))
自底向上的迭代方法:
def fibonacci_dp(n):
if n <= 1:
return n
fib = [0] * (n+1)
fib[1] = 1
for i in range(2, n+1):
fib[i] = fib[i-1] + fib[i-2]
return fib[n]
# 测试
print(fibonacci_dp(10))
案例分析:背包问题
背包问题是另一个经典的动态规划问题。给定一组物品,每个物品都有重量和价值,确定哪些物品应包含在内,以便背包的总重量不超过给定限制且总价值最大。
问题设定
- 物品重量:weights = [1, 3, 4, 5]
- 物品价值:values = [1, 4, 5, 7]
- 背包容量:W = 7
动态规划实现
def knapsack(W, weights, values):
n = len(values)
dp = [[0 for x in range(W+1)] for x in range(n+1)]
for i in range(1, n+1):
for w in range(1, W+1):
if weights[i-1] <= w:
dp[i][w] = max(dp[i-1][w], dp[i-1][w-weights[i-1]] + values[i-1])
else:
dp[i][w] = dp[i-1][w]
return dp[n][W]
# 测试
weights = [1, 3, 4, 5]
values = [1, 4, 5, 7]
W = 7
print(knapsac