From 465dafe9ecc4ce1893b37d075541848cf1073017 Mon Sep 17 00:00:00 2001 From: krahets Date: Mon, 10 Jul 2023 20:36:48 +0800 Subject: [PATCH] Update the text and code of DP. --- .../chapter_dynamic_programming/knapsack.cs | 19 +++++++++++-------- .../chapter_dynamic_programming/knapsack.py | 14 +++++++------- .../dp_solution_pipeline.md | 6 +++--- .../intro_to_dynamic_programming.md | 4 ++-- .../knapsack_problem.md | 2 +- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/codes/csharp/chapter_dynamic_programming/knapsack.cs b/codes/csharp/chapter_dynamic_programming/knapsack.cs index ca1a24566..493085b4e 100644 --- a/codes/csharp/chapter_dynamic_programming/knapsack.cs +++ b/codes/csharp/chapter_dynamic_programming/knapsack.cs @@ -4,7 +4,7 @@ * Author: hpstory (hpstory1024@163.com) */ -namespace hello_algo.chapter_dynamic_programming; +namespace hello_algo.chapter_dynamic_programming; public class knapsack { /* 0-1 背包:暴力搜索 */ @@ -80,7 +80,7 @@ public class knapsack { dp[c] = dp[c]; } else { // 不选和选物品 i 这两种方案的较大值 - dp[c] = Math.Max(dp[c - weight[i - 1]] + val[i - 1], dp[c]); + dp[c] = Math.Max(dp[c], dp[c - weight[i - 1]] + val[i - 1]); } } } @@ -90,12 +90,13 @@ public class knapsack { [Test] public void Test() { int[] weight = { 10, 20, 30, 40, 50 }; - int[] val = { 60, 100, 120, 160, 200 }; + int[] val = { 50, 120, 150, 210, 240 }; int cap = 50; int n = weight.Length; // 暴力搜索 - Console.WriteLine(knapsackDFS(weight, val, n, cap)); + int res = knapsackDFS(weight, val, n, cap); + Console.WriteLine("不超过背包容量的最大物品价值为 " + res); // 记忆化搜索 int[][] mem = new int[n + 1][]; @@ -103,13 +104,15 @@ public class knapsack { mem[i] = new int[cap + 1]; Array.Fill(mem[i], -1); } - - Console.WriteLine(knapsackDFSMem(weight, val, mem, n, cap)); + res = knapsackDFSMem(weight, val, mem, n, cap); + Console.WriteLine("不超过背包容量的最大物品价值为 " + res); // 动态规划 - Console.WriteLine(knapsackDP(weight, val, cap)); + res = knapsackDP(weight, val, cap); + Console.WriteLine("不超过背包容量的最大物品价值为 " + res); // 状态压缩后的动态规划 - Console.WriteLine(knapsackDPComp(weight, val, cap)); + res = knapsackDPComp(weight, val, cap); + Console.WriteLine("不超过背包容量的最大物品价值为 " + res); } } diff --git a/codes/python/chapter_dynamic_programming/knapsack.py b/codes/python/chapter_dynamic_programming/knapsack.py index e776bc2a7..f301eb9db 100644 --- a/codes/python/chapter_dynamic_programming/knapsack.py +++ b/codes/python/chapter_dynamic_programming/knapsack.py @@ -52,7 +52,7 @@ def knapsack_dp(wgt, val, cap): dp[i][c] = dp[i - 1][c] else: # 不选和选物品 i 这两种方案的较大值 - dp[i][c] = max(dp[i - 1][c - wgt[i - 1]] + val[i - 1], dp[i - 1][c]) + dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]) return dp[n][cap] @@ -70,30 +70,30 @@ def knapsack_dp_comp(wgt, val, cap): dp[c] = dp[c] else: # 不选和选物品 i 这两种方案的较大值 - dp[c] = max(dp[c - wgt[i - 1]] + val[i - 1], dp[c]) + dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]) return dp[cap] """Driver Code""" if __name__ == "__main__": wgt = [10, 20, 30, 40, 50] - val = [60, 100, 120, 160, 200] + val = [50, 120, 150, 210, 240] cap = 50 n = len(wgt) # 暴力搜索 res = knapsack_dfs(wgt, val, n, cap) - print(res) + print(f"不超过背包容量的最大物品价值为 {res}") # 记忆化搜索 mem = [[-1] * (cap + 1) for _ in range(n + 1)] res = knapsack_dfs_mem(wgt, val, mem, n, cap) - print(res) + print(f"不超过背包容量的最大物品价值为 {res}") # 动态规划 res = knapsack_dp(wgt, val, cap) - print(res) + print(f"不超过背包容量的最大物品价值为 {res}") # 状态压缩后的动态规划 res = knapsack_dp_comp(wgt, val, cap) - print(res) + print(f"不超过背包容量的最大物品价值为 {res}") diff --git a/docs/chapter_dynamic_programming/dp_solution_pipeline.md b/docs/chapter_dynamic_programming/dp_solution_pipeline.md index f31ae3fb2..0a7b331e5 100644 --- a/docs/chapter_dynamic_programming/dp_solution_pipeline.md +++ b/docs/chapter_dynamic_programming/dp_solution_pipeline.md @@ -7,11 +7,11 @@ ## 问题判断 -总的来说,如果一个问题包含重叠子问题、最优子结构,并满足无后效性,那么它通常就适合用动态规划求解。然而,我们很难从问题描述上直接提取出这些特性。因此我们通常会放宽条件,**先观察问题是否适合使用回溯(穷举)解决**。 +总的来说,如果一个问题包含重叠子问题、最优子结构,并满足无后效性,那么它通常就适合用动态规划求解,但我们很难从问题描述上直接提取出这些特性。因此我们通常会放宽条件,**先观察问题是否适合使用回溯(穷举)解决**。 -**适合用回溯解决的问题通常满足「决策树模型」**,这种问题可以使用树形结构来描述,其中每一个节点代表一个决策,每一条路径代表一个决策序列。 +**适合用回溯解决的问题通常满足“决策树模型”**,这种问题可以使用树形结构来描述,其中每一个节点代表一个决策,每一条路径代表一个决策序列。 -换句话说,**如果问题包含明确的决策概念,并且解是通过一系列决策产生的,那么它就满足决策树模型**,可以使用回溯来解决。 +换句话说,如果问题包含明确的决策概念,并且解是通过一系列决策产生的,那么它就满足决策树模型,通常可以使用回溯来解决。 在此基础上,还有一些判断问题是动态规划问题的“加分项”,包括: diff --git a/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md b/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md index 1f4556c95..127060c8e 100644 --- a/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md +++ b/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md @@ -1,8 +1,8 @@ # 初探动态规划 -「动态规划 Dynamic Programming」是一种用于解决复杂问题的优化算法,它把一个问题分解为一系列更小的子问题,并把子问题的解存储起来以供后续使用,从而避免了重复计算,提升了解题效率。 +「动态规划 Dynamic Programming」是一种通过将复杂问题分解为更简单的子问题的方式来求解问题的方法。它将一个问题分解为一系列更小的子问题,并通过存储子问题的解来避免重复计算,从而大幅提升时间效率。 -在本节中,我们先从一个动态规划的经典例题入手,先给出它的暴力回溯解法,观察其中包含的重叠子问题,再一步步导出更高效的动态规划解法。 +在本节中,我们从一个经典例题入手,先给出它的暴力回溯解法,观察其中包含的重叠子问题,再逐步导出更高效的动态规划解法。 !!! question "爬楼梯" diff --git a/docs/chapter_dynamic_programming/knapsack_problem.md b/docs/chapter_dynamic_programming/knapsack_problem.md index 8cf075936..d0ea0e56c 100644 --- a/docs/chapter_dynamic_programming/knapsack_problem.md +++ b/docs/chapter_dynamic_programming/knapsack_problem.md @@ -6,7 +6,7 @@ !!! question - 给定 $n$ 个物品,第 $i$ 个物品的重量为 $wgt[i-1]$ 、价值为 $val[i-1]$ ,现在有个容量为 $cap$ 的背包,请求解在不超过背包容量下背包中物品的最大价值。 + 给定 $n$ 个物品,第 $i$ 个物品的重量为 $wgt[i-1]$ 、价值为 $val[i-1]$ ,现在有个容量为 $cap$ 的背包,每个物品只能选择一次,问在不超过背包容量下背包中物品的最大价值。 请注意,物品编号 $i$ 从 $1$ 开始计数,数组索引从 $0$ 开始计数,因此物品 $i$ 对应重量 $wgt[i-1]$ 和价值 $val[i-1]$ 。