[CP / Codeforces] DP 的细节处理(一)
最近渐渐地会做一些基础的 DP 题了,但是因为细节上没处理好,常常花很多时间去 debug,导致效率不高,因此打算写这样一篇(一系列)文章分析下 DP 的细节处理。
以这道 1500* 的 E. Block Sequence 为例,当我们得出了:
(点击展开)
在我看来,或者说,在我做了几十道 DP 题之后得出的惨痛教训告诉我,应当先思考两个问题:
- DP 数组的初值是什么?
- DP 数组的边界值是什么?
之所以把边界值放在初值后面考虑,是因为我一般先赋初值再去设置相对较少的边界值,如果倒过来的话,就需要加一些判断语句,否则边界值可能会被初值覆盖。
首先说初值。DP 数组的初值就是我们在执行递推代码前,DP 数组各个元素的初始值。一般来说,如果我们使用 vector 来创建 DP 数组,那么其初值就是 0(假设元素类型是整数)。在很多情况下,不需要特别关注此初值,保持默认的 0 即可,比如统计某某取法的个数啦、判断能获得的最大值啦……这样。然而,我必须说,这是一个坏习惯,因为你不知道什么时候会出问题。
就比如本题。本题求的是最小值,而
因此我建议把初值的设置作为每次做 DP 题时必要的步骤,显式的指明初值 以提醒自己。
注意,初值的具体取值视问题而定,比如背包问题,对于至少 / 恰好 / 至多等限定,需要不同的初值取值。
然后是边界值,可以理解为 dfs 的递归出口条件,根据题意和状态转移方程设置即可。对于线性 DP 来说,一维 DP 一般不会出错,比较容易出错的是高维,因为常常需要设置多个边界值,尤其是在引入降维优化空间复杂度时,我经常忘记设置边界值——不过今天写了这篇文章之后应该不会再犯类似的错误了。
对了,本题题解供参考:
void solve() { int n; std::cin >> n; std::vector<int> v(n); for (int i = 0; i < n; i++) { std::cin >> v[i]; } std::vector<int> dp(n + 1, n); dp[n] = 0; for (int i = n - 1; i >= 0; i--) { dp[i] = dp[i + 1] + 1; if (i + 1 + v[i] <= n) dp[i] = std::min(dp[i], dp[i + 1 + v[i]]); } std::cout << dp[0] << '\n'; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)