记忆化搜索CSP-S

目录

💡 核心思想

记忆化搜索是在递归搜索的基础上,将已计算过的子问题结果缓存起来,避免重复计算。本质上是动态规划的自顶向下实现方式。通常能把指数级复杂度优化为多项式级。

记忆化搜索是理解动态规划的最好跳板。很多同学觉得 DP 难,是因为自底向上的递推不好想。但如果你能用递归把问题想清楚,加上一个备忘录数组,就是记忆化搜索——和 DP 本质相同,只是写法不同。在 CSP 竞赛中,记忆化搜索和递推 DP 都可以,选你更顺手的。

🎯 直觉理解

想象你在解一棵很大的递归树。没有记忆化的话,同样的子问题会被算很多很多次。记忆化就像你在草稿纸上记录:"$f(5)=120$,算过了别再算了"。下次遇到 $f(5)$ 直接查表。

📝 算法流程

  1. 写出朴素的递归搜索
  2. 添加备忘录(数组或map)存储已计算结果
  3. 递归入口先查表:算过直接返回
  4. 没算过则递归计算,存入备忘录后返回

$$\text{朴素斐波那契: } O(2^n) \to \text{记忆化: } O(n)$$

📊 复杂度分析

指标复杂度
时间等于子问题数量 × 每个子问题耗时
空间等于子问题数量

💻 参考实现(C++)

C++ (C++17)
#include <bits/stdc++.h>
using namespace std;
long long memo[1005];
long long fib(int n) {
    if (n <= 1) return n;
    if (memo[n] != -1) return memo[n]; // 查表
    return memo[n] = fib(n-1) + fib(n-2); // 计算+存储
}
int main() {
    memset(memo, -1, sizeof(memo));
    int n; cin >> n;
    cout << fib(n) << endl;
    return 0;
}

⚠️ 常见坑点

备忘录初始化值要和合法答案区分开(如用 -1 表示未计算)

状态设计不合理导致子问题数量爆炸

递归深度过大——可能需要改写为迭代 DP

用 map 做备忘录时常数较大

📚 相关题目

题目来源难度备注
P1048 采药洛谷CSP-J记忆化/01背包
P1434 滑雪洛谷CSP-S记忆化搜索经典题