动态规划
什么是动态规划
动态规划(Dynamic Programming,简称 DP)是一种解决复杂问题的算法思想,通过将问题分解为更小的子问题,并将子问题的解存储起来以避免重复计算,从而提高算法的效率。动态规划通常用于优化问题,即在给定的约束条件下,找到最优解。
动态规划的核心
动态规划中状态是核心,通常用一个或多个变量表示,即dp[i]或dp[i][j],然后用状态转移方程进行推导,但要注意初始状态和边界条件。
使用场景
动态规划适用于具有以下特征的问题:
- 最优子结构:
问题的最优解包含其子问题的最优解,即,可以通过子问题的最优解构造出原问题的最优解。 - 重叠子问题:
问题的递归求解过程中,存在大量的重复计算。动态规划通过存储子问题的解来避免重复计算。
常见应用
背包问题
- 0-1背包
dp[i][j] 表示前 i 种物品在容量为 j 的背包中能达到的最大价值
dp[0][j] = 0:不选任何物品时,价值为0。
dp[i][0] = 0:背包容量为0时,价值为0。
状态转移方程:
dp[i][j]=max(dp[i−1][j],dp[i−1][j−w[i]]+v[i])
1 | int knapsack_01(vector<int>& w, vector<int>& v, int W) { |
- 完全背包
1 | int knapsack_complete(vector<int>& w, vector<int>& v, int W) { |
可以优化
1 | int knapsack_complete(vector<int>& w, vector<int>& v, int W) { |
序列问题
- 最长递增子序列(LIS)
dp[i] 表示以第 i 个元素结尾的最长递增子序列的长度
dp[i] = 1:每个元素自身可以看作一个长度为1的递增子序列。
状态转移方程:
dp[i]=max(dp[i],dp[j]+1)
1 | int n = arr.size(); |
- 最长公共子序列(LCS)
dp[i][j] 表示字符串 X 的前 i 个字符和字符串 Y 的前 j 个字符的最长公共子序列的长度。
dp[0][j] = 0:空字符串与任何字符串的最长公共子序列长度为0。
dp[i][0] = 0:空字符串与任何字符串的最长公共子序列长度为0。
状态转移方程:
如果 X[i−1]==Y[j−1]:
dp[i][j]=dp[i−1][j−1]+1
如果 X[i−1]!=Y[j−1]:
dp[i][j]=max(dp[i−1][j],dp[i][j−1])
1 | int m = X.size(); |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ing的博客!