返回
区间 DP:理解状态转移中的潜在陷阱
前端
2023-09-22 03:25:08
引言
区间 DP 是一种强大的动态规划技术,用于解决涉及区间问题的优化问题。然而,理解状态转移方程对于成功应用区间 DP 至关重要。在这篇文章中,我们将通过 leetcode 每日好题 3.3.3 讨论区间 DP 中状态转移方程的常见陷阱,并提出避免这些陷阱的策略。
每日好题 3.3.3
leetcode 每日好题 3.3.3 要求我们计算将一组气球戳破所需的最小硬币数。气球由一个数组表示,其中每个元素代表一个气球的颜色。戳破一个气球需要消耗与该气球颜色相同的硬币。当一个气球被戳破时,它相邻的两个气球的颜色会合并。
陷阱:气球戳破后的处理
一个常见的陷阱是假设气球戳破后会继续存在。然而,在每日好题 3.3.3 中,气球被戳破后就不复存在了。这意味着在计算状态转移方程时,我们必须考虑戳破后气球消失的情况。
改进的状态转移方程
考虑一个区间 [i, j],其中 i 和 j 是区间内的两个气球索引。设 f[i, j] 为戳破区间 [i, j] 内所有气球所需的最小硬币数。那么,状态转移方程可以表示为:
f[i, j] = min(f[i, k] + f[k + 1, j] + cost[i, j])
其中:
- cost[i, j] 是戳破区间 [i, j] 内所有气球所需的硬币数。
- k 是区间 [i, j] 内的任意分割点。
与传统区间 DP 中的状态转移方程不同,这个方程考虑了戳破气球后气球消失的情况。cost[i, j] 的计算方式如下:
cost[i, j] = if(arr[i] == arr[j]) 0 else c[arr[i]] + c[arr[j]]
其中:
- arr 是气球颜色的数组。
- c[x] 是戳破颜色为 x 的气球所需的硬币数。
代码示例
使用改进后的状态转移方程,我们可以用 C++ 编写以下代码来解决 leetcode 每日好题 3.3.3:
int minCost(vector<int>& arr, int c[]) {
int n = arr.size();
int f[n + 1][n + 1];
memset(f, 0x3f, sizeof(f));
for (int len = 1; len <= n; len++) {
for (int i = 0; i + len - 1 < n; i++) {
int j = i + len - 1;
f[i][j] = cost[i][j];
for (int k = i; k < j; k++) {
f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + cost[i][j]);
}
}
}
return f[0][n - 1];
}
结论
理解状态转移方程对于成功应用区间 DP 至关重要。通过分析 leetcode 每日好题 3.3.3 中气球戳破后的情况,我们发现了一个常见陷阱,并提出了一个改进的状态转移方程来解决这个问题。通过仔细考虑特定问题的细微差别,我们可以避免这些陷阱并编写出有效解决区间 DP 问题的代码。