1. 问题背景与理解
这道题目来自USACO 2007年公开赛的"Cheapest Palindrome G"问题。题目要求我们通过最少的操作成本将一个给定的字符串转换为回文串。允许的操作包括在任意位置添加字符或删除任意位置的字符,每个字符都有对应的添加和删除成本。
回文串是指正读反读都相同的字符串,比如"madam"或"racecar"。这个问题在实际中有很多应用场景,比如DNA序列分析、文本编辑优化等。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路分析
2.1 动态规划与记忆化搜索的选择
传统上,这类问题通常使用动态规划(DP)来解决。但作者在这里选择了记忆化搜索(Memoization)的方法,这是一种自顶向下的递归方法,配合缓存已计算结果来避免重复计算。
记忆化搜索相比DP有几个优势:
- 更直观:直接模拟问题的递归结构
- 更易实现:不需要考虑DP表格的填充顺序
- 可能更高效:只计算必要的子问题
不过记忆化搜索也有缺点,主要是递归深度可能导致栈溢出,但对于本题的字符串长度限制(2000)来说,这不是问题。
2.2 核心递归逻辑
算法的核心在于dfs(l, r)函数,它计算将子串s[l..r]转换为回文的最小成本。函数逻辑如下:
- 基本情况:当l ≥ r时,已经是回文(空串或单字符),成本为0
- 记忆检查:如果已经计算过这个区间,直接返回缓存结果
- 字符匹配:如果两端字符相同,递归处理内部子串
- 字符不匹配:考虑两种操作并取最小值:
- 处理左端:删除左字符或在右端添加匹配字符
- 处理右端:删除右字符或在左端添加匹配字符
3. 代码实现详解
3.1 数据结构选择
cpp复制map<char, int> mp; // 字符到最小操作成本的映射
int vis[N][N]; // 记忆化表格,存储已计算的区间结果
string s; // 输入字符串(1-based索引)
这里作者选择map来存储字符操作成本,虽然查找复杂度是O(log n),但因为字符集有限(26个字母),用数组会更高效。不过对于比赛场景,map足够且更灵活。
3.2 关键函数解析
cpp复制int dfs(int l, int r) {
