概述
线性动态规划(Linear DP)是算法入门中最基础且常见的一类问题。其核心特征是状态转移仅依赖于前一个或前几个状态,状态间呈线性关系,通常可用一维或二维数组存储。
本文通过四道经典例题,从一维到多维逐步深入,演示如何构建状态、推导转移方程以及处理边界条件。代码均使用 C++ 实现,注重逻辑清晰与工程实践。
台阶问题
题目描述
有 N 个台阶,每次可以走 1 到 K 步,求走到第 N 个台阶的方案数。结果对 100003 取模。
解题思路
这道题本质上是斐波那契数列的推广。我们定义 dp[i] 为走到第 i 个台阶的方案数。
-
状态转移 到达第 i 个台阶,可以从
i-1,i-2, ...,i-k处跳过来。因此方案数是这些位置方案数的总和。dp[i] = (dp[i-1] + dp[i-2] + ... + dp[i-k]) % MOD注意数据范围较大,累加过程中需随时取模防止溢出。同时要注意下标不能越界,当
i-j < 0时停止循环。 -
初始化技巧 很多初学者会尝试手动初始化前 k 个状态,但这比较繁琐。更优雅的做法是将
dp[0]设为 1。这代表站在起点(第 0 阶)有一种方案(不动),这样从dp[1]开始递推时,逻辑自然统一。 -
填表顺序 从左往右依次计算即可。
参考实现
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, MOD = 1e5 + 3;
int n, k;
LL dp[N];
int main() {
cin >> n >> k;
// 初始化:起点视为一种方案
dp[0] = 1;
// 循环填表
for (int i = 1; i <= n; i++) {
for (int j = ; j <= k; j++) {
(i - j < ) ;
dp[i] = (dp[i] + dp[i - j]) % MOD;
}
}
cout << dp[n] << endl;
;
}


