区间DP入门
普通区间DP
从某个点到另一个点的连续区间求最优值或计数问题,称为区间DP。
区间DP通常需要使用两维分别表示区间的起始位置与结束位置。
f[i][j]
即表示从 i
到 j
的最优值。
显然,区间DP是从小区间推到大区间,大区间的解是由小区间构成的。
(1)需要控制区间从小到大
模板:先枚举右端点 jjj,再从 jjj 左边继续向左枚举左端点 iii,把区间一点点拉大。
for (int j = 1; j <= n; ++j)for (int i = j-1; i; --i)
这样可以保证,每次要求的区间 f[i][j]
,它的任意一个子区间都是已经求过最优解的。
(2)我们只需要将区间分为两个子区间,将其合并即可,两个子区间各自也是之前由它们各自的子区间合并而来的。
for (int j = 1; j <= n; ++j)for (int i = j-1; i; --i)for (int k = i; k <= j; ++k)f[i][j] = min(f[i][j], f[i][k]+f[k][j]);
所以区间DP的时间复杂度通常是 O(n3)O(n^3)O(n3)。
环形区间DP
还有一类情况的区间DP,整个数列首位相接构成一个环形。
对于这类题目,不论是区间DP,还是以前做过的 字符串移位包含问题,思路都是一样的,即将字符串在末尾再拼接一遍,然后转换为普通的区间DP问题。注意:序列长度仍须维持为原长度,因此需要两个维来控制区间大小,用 f[i][j]
表示区间 [i,j]
的最优解。
对于一个长度为 nnn 的区间,它的起始位置可能有 n(1∼n)n(1\\sim n)n(1∼n) 种,对应的结束位置也有 n(n∼2n−1)n(n\\sim 2n-1)n(n∼2n−1) 种。
通常需要更新 f[i][i]
。
for (int j = 1; j < (n<<1); ++j)for (int i = j-1; i > j-n; --i)//控制区间长度不能超过nfor (int k = i; k <= j; ++k)f[i][j] = min(f[i][j], f[i][k]+f[k][j]);