【概述】
区间型动态规划,又称为合并类动态规划,是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的区间中哪些元素合并而来有很大的关系。
【思想】
区间 DP 实质上就是在一个区间上进行的动态规划,不仅要满足 DP 问题的最优子结构,还要符合在区间上操作的特点。
其主要思想就是在小区间进行 DP 得到最优解,然后再利用小区间的最优解合并求大区间的最优解。
往往会枚举区间,将区间分成左右两部分,再求出左右区间进行合并操作。这样一来,如果要得知一个大区间的情况,由于它必定是由从多个长度不一的小区间转移而来,那么可以通过求得多个小区间的情况,从而合并信息,得到大区间。
即:已知区间长度为 len-1 的所有状态,然后可以通过小于 len 的状态转移到区间长度为 len 的状态,一般是在外层循环遍历 len,内层循环遍历起点来解决。
for k:=1 to n-1 do //区间长度
for i:=1 to n-k do //区间起点
for j:=i to i+k-1 do //区间中任意点
dp[i,i+k]:=max{dp[i,j] + dp[j+1,i+k] + a[i,j] + a[j+1,i+k]};
状态转移方程:寻找区间 dp[i,i+k] 的一种合并方式 dp[i,j] + dp[j+1,i+k],使得其值最大或最小
区间长度 k 必须要放到第一层循环,来保证方程中状态 dp[i,j]、dp[j+1,i+k] 值在 dp[i,i+k] 之前就已计算出来
其中 a[i,j]+a[j+1,i+k] 可以灵活多变,其指的是合并区间时产生的附加值
【模板】
区间 DP 中常见的题型,其基本都可以按照以下的套路来解决,只是不同的题设对应的状态转移方程不同。
此外,石子合并问题是区间 DP 中的经典模型,具体内容见:石子合并三讲
int dp[N][N];
for(int i=1;i<=n;i++)
dp[i][i]=初始值
for(int len=2;len<=n;len++){ //区间长度
for(int i=1;i<=n;i++){ //枚举起点
int j=i+len-1; //区间终点
if(j>n) //越界结束
break;
for(int k=i;k<j;k++) //枚举分割点,构造状态转移方程
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
}
}
【例题】
1.简单区间 DP
- Multiplication Puzzle(POJ-1651):点击这里
- 传球游戏(洛谷-P1057):点击这里
- 释放囚犯(洛谷-P1622):点击这里
- Halloween Costumes(LightOJ-1422):点击这里
2.石子合并
- 合并石子(信息学奥赛一本通-T1274)(直线合并求最大):点击这里
- 石子合并问题--直线版(Hrbust-1818)(直线合并求最小):点击这里
- 石子合并(洛谷-P1880)(环形合并):点击这里
- 能量项链(NOIP-2006 提高组)(环形合并):点击这里
3.其他
- Running(POJ-3661)(分治+区间DP):点击这里
- You Are the One(HDU-4283)(前缀和+区间DP):点击这里
- String painter(HDU-2476)(线性DP+区间DP):点击这里
- Cheapest Palindrome(POJ-3280)(递推+区间DP):点击这里
- Brackets(POJ-2955)(匹配个数+区间DP):点击这里
- Brackets Sequence(POJ-1141)(递归输出+区间DP):点击这里
- Palindrome subsequence(HDU-4632)(回文串子序列):点击这里
- Two Rabbits(HDU-4757)(非连续最长回文子序列):点击这里