mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-09 05:56:06 +00:00
build
This commit is contained in:
@@ -2,14 +2,14 @@
|
||||
comments: true
|
||||
---
|
||||
|
||||
# 13.3. 动态规划解题思路
|
||||
# 14.3. 动态规划解题思路
|
||||
|
||||
上两节介绍了动态规划问题的主要特征,接下来我们一起探究两个更加实用的问题:
|
||||
|
||||
1. 如何判断一个问题是不是动态规划问题?
|
||||
2. 求解动态规划问题该从何处入手,完整步骤是什么?
|
||||
|
||||
## 13.3.1. 问题判断
|
||||
## 14.3.1. 问题判断
|
||||
|
||||
总的来说,如果一个问题包含重叠子问题、最优子结构,并满足无后效性,那么它通常就适合用动态规划求解,但我们很难从问题描述上直接提取出这些特性。因此我们通常会放宽条件,**先观察问题是否适合使用回溯(穷举)解决**。
|
||||
|
||||
@@ -29,7 +29,7 @@ comments: true
|
||||
|
||||
如果一个问题满足决策树模型,并具有较为明显的“加分项“,我们就可以假设它是一个动态规划问题,并尝试求解它。
|
||||
|
||||
## 13.3.2. 问题求解
|
||||
## 14.3.2. 问题求解
|
||||
|
||||
动态规划的解题流程可能会因问题的性质和难度而有所不同,但通常遵循以下步骤:描述决策,定义状态,建立 $dp$ 表,推导状态转移方程,确定边界条件等。
|
||||
|
||||
@@ -99,7 +99,7 @@ $$
|
||||
|
||||
接下来,我们就可以实现动态规划代码了。然而,由于子问题分解是一种从顶至底的思想,因此按照“暴力搜索 $\rightarrow$ 记忆化搜索 $\rightarrow$ 动态规划”的顺序实现更加符合思维习惯。
|
||||
|
||||
## 13.3.3. 方法一:暴力搜索
|
||||
## 14.3.3. 方法一:暴力搜索
|
||||
|
||||
从状态 $[i, j]$ 开始搜索,不断分解为更小的状态 $[i-1, j]$ 和 $[i, j-1]$ ,包括以下递归要素:
|
||||
|
||||
@@ -240,7 +240,7 @@ $$
|
||||
|
||||
每个状态都有向下和向右两种选择,从左上角走到右下角总共需要 $m + n - 2$ 步,所以最差时间复杂度为 $O(2^{m + n})$ 。请注意,这种计算方式未考虑临近网格边界的情况,当到达网络边界时只剩下一种选择。因此实际的路径数量会少一些。
|
||||
|
||||
## 13.3.4. 方法二:记忆化搜索
|
||||
## 14.3.4. 方法二:记忆化搜索
|
||||
|
||||
为了避免重复计算重叠子问题,我们引入一个和网格 `grid` 相同尺寸的记忆列表 `mem` ,用于记录各个子问题的解,提升搜索效率。
|
||||
|
||||
@@ -394,7 +394,7 @@ $$
|
||||
|
||||
<p align="center"> Fig. 记忆化搜索递归树 </p>
|
||||
|
||||
## 13.3.5. 方法三:动态规划
|
||||
## 14.3.5. 方法三:动态规划
|
||||
|
||||
动态规划代码是从底至顶的,仅需循环即可实现。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user