动态规划(Dynamic Programming, DP)

简介: 动态规划(Dynamic Programming, DP)

动态规划(Dynamic Programming, DP)是一种通过将问题分解为更小的子问题,并存储这些子问题的解来避免重复计算的方法。它通常用于解决具有重叠子问题和最优子结构性质的问题。

1. 基本概念

动态规划的核心思想是将复杂问题分解为简单的子问题,并通过存储这些子问题的解来提高效率。动态规划通常使用一个表格(数组或字典)来存储子问题的解,以避免重复计算。

2. 示例:斐波那契数列

斐波那契数列是一个经典的动态规划问题。我们可以通过自底向上的方式实现它,从而避免递归中的大量重复计算。

实现代码

def fibonacci(n):
    if n <= 0:
        return 0
    elif n == 1:
        return 1

    # 创建一个数组来存储子问题的解
    dp = [0] * (n + 1)
    dp[1] = 1

    # 填充数组
    for i in range(2, n + 1):
        dp[i] = dp[i - 1] + dp[i - 2]

    return dp[n]

# 测试
print(fibonacci(6))  # 输出 8

在这个例子中,我们使用一个数组 dp 来存储从 0n 的斐波那契数。通过迭代填充这个数组,我们避免了递归中的重复计算。

3. 示例:背包问题

背包问题是另一个经典的动态规划问题。假设你有一个容量为 W 的背包和 n 个物品,每个物品有一个重量和一个价值。目标是选择一些物品放入背包,使得总价值最大且总重量不超过 W

实现代码

def knapsack(weights, values, W):
    n = len(weights)
    # 创建一个二维数组来存储子问题的解
    dp = [[0 for _ in range(W + 1)] for _ in range(n + 1)]

    # 填充数组
    for i in range(1, n + 1):
        for w in range(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, 2, 3]
values = [6, 10, 12]
W = 5
print(knapsack(weights, values, W))  # 输出 22

在这个例子中,我们使用一个二维数组 dp 来存储子问题的解。dp[i][w] 表示前 i 个物品在容量为 w 的背包中的最大价值。通过迭代填充这个数组,我们可以找到最优解。

4. 示例:最长公共子序列(LCS)

最长公共子序列是另一个常见的动态规划问题。给定两个字符串,找到它们的最长公共子序列的长度。

实现代码

def longest_common_subsequence(X, Y):
    m = len(X)
    n = len(Y)
    # 创建一个二维数组来存储子问题的解
    dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]

    # 填充数组
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if X[i - 1] == Y[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

    return dp[m][n]

# 测试
X = "AGGTAB"
Y = "GXTXAYB"
print(longest_common_subsequence(X, Y))  # 输出 4

在这个例子中,我们使用一个二维数组 dp 来存储子问题的解。dp[i][j] 表示字符串 X 的前 i 个字符和字符串 Y 的前 j 个字符的最长公共子序列的长度。通过迭代填充这个数组,我们可以找到最长公共子序列的长度。

5. 注意事项

  • 状态定义:明确定义子问题的状态,这是动态规划的关键。
  • 状态转移方程:找出子问题之间的关系,即状态转移方程。
  • 初始条件:确定边界条件,通常是最小的子问题。
  • 空间优化:有时可以通过滚动数组等技术来优化空间复杂度。

通过这些示例和注意事项,你可以在 Python 中有效地实现和使用动态规划来解决各种复杂的问题。

目录
相关文章
|
存储 算法 Python
算法专题1——动态规划 Dynamic Programming,DP
算法专题1——动态规划 Dynamic Programming,DP
102 0
|
6月前
|
SQL 算法 数据挖掘
动态规划Dynamic programming详解-编辑距离问题【python】
动态规划Dynamic programming详解-编辑距离问题【python】
|
6月前
|
人工智能
|
6月前
|
存储 算法 Java
动态规划详解(Dynamic Programming)
动态规划详解(Dynamic Programming)
67 1
|
6月前
|
存储 SQL 算法
动态规划Dynamic programming详解-背包问题【python】
动态规划Dynamic programming详解-背包问题【python】
|
6月前
|
存储 算法 数据挖掘
动态规划Dynamic programming详解-最长公共子序列【python】
动态规划Dynamic programming详解-最长公共子序列【python】
|
6月前
|
存储 SQL 算法
动态规划Dynamic programming详解-硬币找零问题【python】
动态规划Dynamic programming详解-硬币找零问题【python】
|
7月前
动态规划(Dynamic Programming)详解
动态规划(Dynamic Programming)详解
41 0
|
7月前
|
机器人
动态规划Dynamic Programming
动态规划Dynamic Programming
49 0
|
7月前
|
机器学习/深度学习 存储 算法
算法·动态规划Dynamic Programming
算法·动态规划Dynamic Programming
45 0