区间 DP
区间 DP
DP回顾
DP三个特征(基本条件):
- 重叠子问题
- 最优子结构
- 无后效性
重叠子问题:就是影响到前面的
最优子结构:局部是最优的,北京到上海是北京到杭州的子结构
无后效性:大不影响小
思考:DP和搜索的区别?
引导题目
连一条线然后启动分离 改编题:

eg1-石子合并问题
问题描述:
有N堆石子排成一排,每堆石子有一定的数量。
现要将N堆石子合并成一堆。合并的过程只能每次将相邻的两堆石子并成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求总的代价最小值。
题目来源——NOI1995
选中一个位置,左右两侧是互相独立的子问题→可以递推
题目特点分析:
1、求某个区间的最优解(一般是区间\([1,
n]\));
2、大的区间由包含于它的小区间组成(转移而来);
3、满足DP的三个基本条件;
状态,阶段,决策(状态转移)
- 题目分析:
- 状态
- 通用状态的定义:\(\text{DP}[i][j]\)的含义?
- 目标状态的表示:???
- 阶段的划分:区间长度
- 决策(状态转移): \(\text{dp}[i][j]=\min(\text{dp}[i][j], \text{dp}[i][k]+\text{dp}[k+1][j]+\text{w}[i][j])\)
i 到 j 需要的体力值
区间DP小结
- 阶段的划分:区间长度
- 状态的表示:枚举起点(不同起点,不同状态)
- 决策的实现:枚举分割点
区间DP的状态设计相对简单,基本大部分问题都是用
dp[i][j] 代表区间 [i,j] 上的最优解。
状态转移一定是从区间长度短的状态到区间长度长的状态;
代码:
递推迭代
区间DP模板-迭代:
for(int len=2;len<=n;len++) //区间长度 |
记忆化DFS(推荐
区间DP模板-记忆化DFS:
//推荐记忆化DFS的实现方式,更简单,不容易出错
int MINdfs(int l,int r) |
最大值则改为 max,还有初始化用 -1
eg2-猴子交朋友
n只猴子坐成一圈,每只猴子都有交朋友的时间,交友规则是:
- 每次只能介绍一只猴子和这只猴子的邻居认识(成为朋友);
- 如果介绍猴子A和B认识,那么意味着猴子A和B将认识对方的所有朋友,这次交友的总用时是A和B原来交友时间的总和;
- 每个猴子都认识自己;
求完成交友任务(所有猴子都相互认识)需要的最短时间。
是一个环形石子合并
问题分析
问题的本质? ——环形石子合并!
即现在有围成一圈的若干堆石子,求合并所需最小代价。
环形问题转化小技巧:
把前n-1堆石子一个个移到第n个后面,那样环就变成了线,即转化成了有2*n-1堆石子的普通石子合并问题。
最后求:\(\boldsymbol{\min(\mathrm{dp}[s][s+n-1]), s \in [1, n]}\)
eg3-狼
有N匹狼站成一排(从左到右编号为1到N),你必须打败所有的狼才能生存。
每匹狼具有一定的基本攻击力a[i]和辅助攻击力b[i]
杀一匹狼消耗的能量 = 狼的基本攻击力a[i]+相邻两匹狼的辅助攻击力b[i-1]+b[i+1]。
求打败所有的狼所需要的最小能量。
特别说明:如果杀死第k个位置的狼,则接下来k-1和k+1位置的狼变为相邻,以此类推。
题目来源——2014ACM/ICPC亚洲区北京站
题目解析
递推公式,解决:
状态定义:
dp[i][j]——表示从第i头狼到第j头狼全部被杀死所需要的最少能量。
目标状态: dp[1][n]
状态转移:
dp[i][j] = min(dp[i][j], dp[i][k-1]+dp[k+1][j] + a[k]+b[i-1] + b[j+1]);
小细节: b[0] = b[n+1] = 0;
即左右两侧只能用到各1次
eg4-焦躁因子
一个有点难度的区间DP:
在《非诚勿扰》节目中,给定n个男生的序列,序列内的每个人都有一个焦躁因子Di,如果第i个人是第k个出场,那么他的焦躁值为Di * (k-1), 现在,导演可以通过一个栈来调整序列里面人的出场顺序。 求焦躁总值最小可以是多少。
题目来源——2012 ACM/ICPC Asia Regional Tianjin Online
题目解析
分成两个子问题,1在k处释放
关键点——
导演对于男生出场顺序的影响是有限的! 比如:
- 如果,第一个人第k个出场;
- 那么,第2 ~ k的人都要在第一个人前面出场;
- 同时,第k+1 ~ n的人都要在k以后出场。
大区间问题 划分成了 小区间的问题。
解决,转移方程
定义状态\(dp[i, j]\)表示,对于区间\([i, j]\)在相对于\(i\)为起点情况下,最小焦躁总值。
\(dp[1, n]\)就是所要求的值。
状态转移方程是——
\[dp[i, j] = (k-i) * Di + dp[i+1, k] + dp[k+1, j] + (k+1-i) * (sum[j] - sum[k])\]
更多练习
参考资料和相关题目
多边形剖分、括号匹配、回文串(IOI2000) 石子合并(NOI1995)、能量项链(NOIP2006)
https://mp.weixin.qq.com/s/vw-Wunkm_zoJMPAZygnW2w
https://www.cnblogs.com/kedebug/archive/2012/12/10/2811053.html
https://blog.csdn.net/my_sunshine26/article/details/77141398
总结
区间DP常规思路总结:
1、切割/合并区间 将大区间无脑切割成两个子区间,分别计算两个子区间的最优值,再通过两个子区间的最优值,计算整个大区间的最优值。
2、last原则 永远不去想第一步要干什么,而是想最后一步是要干什么,然后再去枚举最后一步的所有情况,从而缩小区间。
3、添加辅助维 有时候二维的区间无法表示状态,或者无法进行状态转移的时候,我们可以尝试再增加一个纬度,然后再去想状态转移方程。