1、动态规划算法解题
LeetCode 931. 下降路径最小和
给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。
下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 。
1. 自底向上,迭代,dp数组
class Solution {
public:
int minFallingPathSum(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<vector<int>> dp(m, vector<int>(n));
for (int j=0; j<n; j++){
dp[m-1][j] = matrix[m-1][j];
}
for (int i=m-2; i>=0; i--){
for (int j=0; j<n; j++){
dp[i][j] = matrix[i][j] + dp[i+1][j];
if (j-1 >= 0) dp[i][j] = min(dp[i][j], matrix[i][j] + dp[i+1][j-1]);
if (j+1 < n) dp[i][j] = min(dp[i][j], matrix[i][j] + dp[i+1][j+1]);
}
}
int res = INT_MAX;
for (int j=0; j<n; j++){
res = min(res, dp[0][j]);
}
return res;
}
};
2. 自顶向下,递归,备忘录memo
class Solution {
public:
vector<vector<int>> memo;
int minFallingPathSum(vector<vector<int>>& matrix) {
int res = 99999;
int n = matrix.size();
memo.resize(n, vector<int>(n, 99999));
for (int j = 0; j < n; j++) res = min(res, dp(matrix, n-1, j));
return res;
}
int dp(vector<vector<int>>& matrix, int i, int j){
if (i < 0 || j < 0 || i > matrix.size()-1 || j > matrix[0].size()-1)
return 66666;
// base case
if (i == 0) return matrix[0][j];
// 查找备忘录
if (memo[i][j] != 99999) return memo[i][j];
// 状态转移
memo[i][j] = min(min(dp(matrix, i-1, j-1), dp(matrix, i-1, j)), dp(matrix, i-1, j+1)) + matrix[i][j];
return memo[i][j];
}
};
2、强化学习 - 动态规划算法
动态规划(Dynamic Programming, DP)是强化学习中基于模型(model-based)方法的核心,通过已知的环境模型(状态转移概率和回报函数)利用贝尔曼方程(Bellman Equation)反复计算值函数,从而推导出最优策略。
动态规划方法假设智能体拥有环境的完美模型,即知道在任何状态下采取任何动作所带来的即时奖励以及转移到下一个状态的概率。动态规划主要用于解决强化学习中的“规划”问题,即在已知环境动力学的情况下找到最优策略。
- 在DP框架下:策略评估(Policy Evaluation)与策略改进(Policy Improvement)
- 两大类算法:策略迭代(Policy Iteration)与值迭代(Value Iteration)
2.1. 背景知识
马尔可夫决策过程(MDP)
MDP定义:一个MDP由五元组 ( S , A , P , R , γ ) (\mathcal{S}, \mathcal{A}, P, R, \gamma) (S,A,P,R,γ) 构成,其中 S \mathcal{S} S 是状态集合, A \mathcal{A} A 是动作集合, P ( s ′ ∣ s , a ) P(s'|s,a) P(s′∣s,a) 是状态转移概率, R ( s , a , s ′ ) R(s,a,s') R(s,a,s′) 是即时回报, γ ∈ [ 0 , 1 ) \gamma\in[0,1) γ∈[0,1) 是折扣因子。
值函数:状态价值函数 V π ( s ) V^\pi(s) Vπ(s) 表示在策略 π \pi π 下从状态 s s s 开始获得的期望累积折扣回报;动作价值函数 Q π ( s , a ) Q^\pi(s,a) Qπ(s,a) 则表示在状态 s s s 执行动作 a a a 后执行策略 π \pi π 的期望价值。
2.2. 动态规划原理
动态规划利用已知的MDP模型,基于贝尔曼方程迭代计算值函数,并根据值函数更新策略,直至收敛到最优策略。
1. 策略评估(Policy Evaluation)
策略评估的目标是在给定策略 π \pi π 下,反复应用贝尔曼期望方程
V k + 1 ( s ) = ∑ a π ( a ∣ s ) ∑ s ′ , r P ( s ′ , r ∣ s , a ) [ r + γ V k ( s ′ ) ] V_{k+1}(s) = \sum_{a}\pi(a|s)\sum_{s',r}P(s',r|s,a)\bigl[r + \gamma V_k(s')\bigr] Vk+1(s)=a∑π(a∣s)s′,r∑P(s′,r∣s,a)[r+γVk(s′)]
直至 ∥ V k + 1 − V k ∥ ∞ < θ \|V_{k+1} - V_k\|_\infty < \theta ∥Vk+1−Vk∥∞<θ(阈值)
- 符号说明:
- π ( a ∣ s ) \pi(a|s) π(a∣s):策略 π \pi π在状态 s s s下选择动作 a a a的概率。
- r ( s , a ) r(s,a) r(s,a):在状态 s s s采取动作 a a a的即时奖励。
- γ \gamma γ:折扣因子( 0 ≤ γ ≤ 1 0 \leq \gamma \leq 1 0≤γ≤1),表示未来奖励的权重。
- P ( s ′ , r ∣ s , a ) P(s',r|s,a) P(s′,r∣s,a):状态转移概率,表示在状态 s s s采取动作 a a a后转移到状态 s ′ s' s′、获得及时奖励 r r r的概率。
- V k ( s ′ ) V_k(s') Vk(s′):下一状态 s ′ s' s′的值函数。
2. 策略迭代(Policy Iteration)
初始化:任意初始化策略 π 0 \pi_0 π0 和相应的 V ( s ) V(s) V(s)。
策略评估:对当前策略 π k \pi_k πk 执行上述策略评估,获得 V π k V^{\pi_k} Vπk。
策略改进:对所有状态 s s s,更新策略
π k + 1 ( s ) = arg max a ∑ s ′ , r P ( s ′ , r ∣ s , a ) [ r + γ V π k ( s ′ ) ] . \pi_{k+1}(s) = \arg\max_a \sum_{s',r} P(s',r|s,a)\bigl[r + \gamma V^{\pi_k}(s')\bigr]. πk+1(s)=argamaxs′,r∑P(s′,r∣s,a)[r+γVπk(s′)].
重复 步骤 2–3,直到策略不再改变。
该算法保证在有限步数内收敛到最优策略 π ∗ \pi^* π∗.
3. 值迭代(Value Iteration)
值迭代将策略评估与策略改进合并:
V k + 1 ( s ) = max a ∑ s ′ , r P ( s ′ , r ∣ s , a ) [ r + γ V k ( s ′ ) ] , V_{k+1}(s) = \max_{a}\sum_{s',r}P(s',r|s,a)\bigl[r + \gamma V_k(s')\bigr], Vk+1(s)=amaxs′,r∑P(s′,r∣s,a)[r+γVk(s′)],
直至 ∥ V k + 1 − V k ∥ ∞ < θ \|V_{k+1} - V_k\|_\infty < \theta ∥Vk+1−Vk∥∞<θ,然后由最终的 V ∗ V^* V∗ 直接提取最优策略:
π ∗ ( s ) = arg max a ∑ s ′ , r P ( s ′ , r ∣ s , a ) [ r + γ V ∗ ( s ′ ) ] \pi^*(s)=\arg\max_a\sum_{s',r}P(s',r|s,a)[r+\gamma V^*(s')] π∗(s)=argamaxs′,r∑P(s′,r∣s,a)[r+γV∗(s′)]
实现步骤
算法伪代码
输入:MDP模型 (S, A, P, R, γ), 收敛阈值 θ
输出:最优策略 π*, 最优值函数 V*
1. 初始化 V(s) 任意;π(s) 任意
2. 重复:
a. Δ ← 0
b. 对于每个状态 s ∈ S:
v ← V(s)
V(s) ← max_a ∑_{s',r} P(s',r|s,a)[ r + γ V(s') ]
Δ ← max(Δ, |v - V(s)|)
c. 直到 Δ < θ
3. 对于每个 s ∈ S:
π(s) ← argmax_a ∑_{s',r} P(s',r|s,a)[ r + γ V(s') ]
4. 返回 π, V
上述即为值迭代的核心伪代码,策略迭代只需将步骤 2b 中“max”替换为按当前π评估,并在评估后插入策略改进步骤。
Python 实现示例
def value_iteration(P, R, gamma=0.9, theta=1e-6):
"""
P: dict, P[s][a] = list of (prob, next_s, reward)
R: dict, immediate rewards R[s][a][s']
"""
V = {s: 0.0 for s in P}
while True:
delta = 0
for s in P:
v_old = V[s]
V[s] = max(
sum(prob * (r + gamma * V[s_next])
for prob, s_next, r in P[s][a])
for a in P[s]
)
delta = max(delta, abs(v_old - V[s]))
if delta < theta:
break
# 策略提取
policy = {}
for s in P:
policy[s] = max(
P[s].keys(),
key=lambda a: sum(prob * (r + gamma * V[s_next])
for prob, s_next, r in P[s][a])
)
return policy, V
注意事项
- 收敛性:DP方法在折扣因子 γ < 1 \gamma<1 γ<1 或有终止状态的有限MDP中保证收敛。
- 计算复杂度:状态-动作空间过大(例如上百维状态)时,DP算法不可行,需要采用抽样或函数逼近方法(如TD、DQN等)。
- 异步DP:可采用异步更新(Asynchronous DP)和广义策略迭代(Generalized Policy Iteration)以提升效率。