6854: 学习系列 —— 动态规划 —— 区间DP(I)—— 线性
[Creator : ]
Description
定义
区间 DP 就是在区间上进行动态规划,求解一段区间上的最优解。主要是通过合并小区间的最优解进而得出整个大区间上最优解的 DP 算法。区间类动态规划是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来有很大的关系。
令状态 $f(i,j)$ 表示将下标位置 $i$ 到 $j$ 的所有元素合并能获得的价值的最大值,那么 $f(i,j)=\text{max}\{f(i,k)+f(k+1,j)+\text{cost} \}$,$\text{cost}$ 为将这两组元素合并起来的代价。
性质
区间 DP 有以下特点:合并:即将两个或多个部分进行整合,当然也可以反过来;
特征:能将问题分解为能两两合并的形式;
求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问题的最优值。
核心思路
既然让我求解在一个区间上的最优解,那么我把这个区间分割成一个个小区间,求解每个小区间的最优解,再合并小区间得到大区间即可。所以在代码实现上,我可以枚举区间长度 len 为每次分割成的小区间长度(由短到长不断合并),内层枚举该长度下可以的起点,自然终点也就明了了。然后在这个起点终点之间枚举分割点,求解这段小区间在某个分割点下的最优解。例如:对于区间 $[i,j]$,它的合并方式有很多种,可以是 $[i,i+1]$ 和 $[i+2,j]$ 也可以是 $i,k]$ 和 $[k+1,j]$(其中 $i \leq k < j$)……
Input
模板代码
for (int len = 1; len <= n; len++) { // 区间长度 for (int i = 1; i + len - 1 <= n; i++) { // 枚举起点 int j = i + len - 1; // 区间终点 if (len == 1) { dp[i][j] = 初始值 continue; } for (int k = i; k < j; k++) { // 枚举分割点,构造状态转移方程 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + w[i][j]); } } }