区间DP入门

普通区间DP

这种从某个点到达某个点的最优值或计数问题,可以建模为一个区间的问题,称为区间DP。

区间DP通常需要两维表示区间的起始位置与结束位置。

f[i][j] 即表示从 ij 的最优值。

显然,区间DP是从小区间推到大区间,大区间的解是由小区间构成的。

(1)需要控制区间从小到大

模板:先枚举右端点 j j j,再从 j j j 左边继续向左枚举左端点 i i i,把区间一点点拉大。

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 ( n 3 ) O(n^3) O(n3)

环形区间DP

还有一类情况的区间DP,整个数列首位相接构成一个环形。

对于这类题目,不论是区间DP,还是以前做过的 字符串移位包含问题,思路都是一样的,即将字符串在末尾再拼接一遍,然后转换为普通的区间DP问题。注意:序列长度仍然维持为原长度,因此需要两个维来控制区间大小,用 f[i][j] 表示区间 [i,j] 的最优解。
对于一个长度为 n n n 的区间,它的起始位置可能有 n ( 1 ∼ n ) n(1\sim n) n(1n) 种,对应的结束位置也有 n ( n ∼ 2 n − 1 ) n(n\sim 2n-1) n(n2n1) 种。
通常需要更新 f[i][i][1]

for (int j = 1; j < (n<<1); ++j)
	for (int i = j-1; i > j-n; --i)//控制区间长度不能超过n
		for (int k = i; k <= j; ++k)
			f[i][j] = min(f[i][j], f[i][k]+f[k][j]);

你可能感兴趣的:(DP,动态规划,c++,算法)