动态规划 (Dynamic Programming) 是一种算法思想,用于解决一些复杂的问题。本文将介绍动态规划的分类、概念和经典例题讲解。
动态规划可以分为以下两种类型:
在解决动态规划问题时,我们需要定义以下概念:
下面我们将分别介绍0/1背包问题和最长公共子序列问题的解法。
题目描述:有n个物品和一个容量为W的背包。第i个物品的重量为wi,价值为vi。现在,需要选择一些物品放入背包,使得放入的物品的总重量不超过W,且总价值最大。求最大价值。
解题思路:定义状态dp[i][j]为在使用前i个物品时,填满j容量的背包的最大价值。状态转移方程如下所示:
d
p
[
i
]
[
j
]
=
{
d
p
[
i
−
1
]
[
j
]
,
j
<
w
i
max
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
w
i
]
+
v
i
)
,
j
≥
w
i
dp[i][j] =
代码实现:
int dp[101][1001];
int weight[101], value[101];
int knapSack(int n, int w)
{
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= w; j++) {
if (j < weight[i]) {
dp[i][j] = dp[i-1][j];
} else {
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i]);
}
}
}
return dp[n][w];
}
题目描述:给定两个字符串A和B,找到它们的最长公共子序列 (LCS)。
解题思路:定义状态dp[i][j]为字符串A的前i个字符和字符串B的前j个字符的LCS长度。状态转移方程如下所示:
d
p
[
i
]
[
j
]
=
{
0
,
i
=
0
或
j
=
0
d
p
[
i
−
1
]
[
j
−
1
]
+
1
,
A
i
=
B
j
max
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
,
A
i
≠
B
j
dp[i][j] =
当A[i-1]等于B[j-1]时,dp[i][j]等于dp[i-1][j-1]+1,表示A和B中的相同字符加上它们前面的LCS。当它们不相等时,LCS为它们前面的LCS的最大值,即dp[i-1][j]和dp[i][j-1]的最大值。
代码实现:
int dp[1001][1001];
string A, B;
int LCS(int n, int m)
{
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++) {
if (i == 0 || j == 0) {
dp[i][j] = 0;
} else if (A[i-1] == B[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[n][m];
}
动态规划是一种非常重要的算法思想,它通常用于解决复杂的问题。在应用动态规划解决问题时,需要注意定义状态、状态转移方程、初始状态和边界状态等概念。对于不同类型的动态规划问题,需要采用不同的解决方法。希望本文能够帮助读者加深对动态规划的理解。