C/C++ 动态规划入门:多状态 DP 实战
绪论
本章是动态规划的进阶篇。从基础的一维 DP、二维路径问题,我们逐步深入到多状态 DP。本章将结合前面的基础,由浅入深地讲解多状态问题的建模思路,涵盖经典的'打家劫舍'系列到复杂的'股票买卖'系列。过程中会不断总结规律,帮助大家建立通用的解题框架。
提示:若对基础 DP 尚不熟悉,建议先复习一维 DP 和路径 DP 相关章节。
打家劫舍系列
遇到相邻元素不能同时选择的场景时,往往可以联想到打家劫舍模型。这类问题通常使用两个 DP 表来分别存储不同状态下的最优解。
f[i]:选择第 i 个位置时的最大价值g[i]:不选择第 i 个位置时的最大价值
1. 按摩师(LeetCode 面试题)
题目描述:
给定一个整数数组 nums,表示每个预约的时长。不能连续选择相邻的预约,求最长预约总时长。
分析: 这是一个典型的线性 DP 问题。对于每个位置,我们有两种选择:选或不选。
-
状态定义:
dp[i][0](或f[i]):选择第 i 个预约时的最大时长。dp[i][1](或g[i]):不选择第 i 个预约时的最大时长。
-
状态转移:
- 如果选择第 i 个,则前一个必须不选:
f[i] = g[i-1] + nums[i] - 如果不选第 i 个,则前一个可选可不选,取最大值:
g[i] = max(f[i-1], g[i-1])
- 如果选择第 i 个,则前一个必须不选:
-
初始化:
- 处理边界情况,当
n=0时直接返回 0。 f[0] = nums[0],g[0] = 0
- 处理边界情况,当
-
返回值:
max(f[n-1], g[n-1])
代码实现:
class Solution {
public:
int massage(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
vector<int> f(n, );
;
f[] = nums[];
( i = ; i < n; i++) {
f[i] = g[i - ] + nums[i];
g[i] = (f[i - ], g[i - ]);
}
(f[n - ], g[n - ]);
}
};


