dp做题集锦(持续更新中)

最近做了些dp题,看看题目吧
对于我这种菜鸡可能比较有价值,大佬基本就别看了

关路灯

题目传送门
放下Codevs的,感觉这里的数据规模比较适合。其他网站数据的太弱了
我们可以很轻易地想到,经过了一盏灯就一定要把它顺手关掉
那么可能我在经过某一段区间之后要回头,那么这一段区间我肯定要全部关掉
那么,我们令  f(i,j,0) 表示对于  [i,j] 这一段区间,我最后停留在点  i 最少要消耗的电功是多少;同理,  f(i,j,1) 就表示停留在  j 点的时候了
我们只看  f(i,j,0) 的求解方式,因为  f(i,j,1) 和其类似
考虑最后停留在点  i 的话,可能从哪些点走过来
方向肯定是向左,所以我们只需考虑在  [i+1,j] 这段区间走过来即可
那么,只可能从  i+1 或者  j 点走过来
我们仔细想一想,最后的答案和时间的关系并没有那么大,我们只需要记录消耗了多少功即可
为什么? 我们可以这样理解,没有关灯的代价已经在电功里面了
那么我们可以得到转移方程:

f(i,j,0)=min(f(i+1,j,0)+(Ss(i+1,j))(pos[i+1]pos[i]),f(i+1,j,1)+(Ss(i+1,j))(pos[j]pos[i]))

类似于  f(i,j,0) 的求法,我们依然可以求解  f(i,j,1)

时间复杂度?  O(n2)
还是比较优秀的
主要算法:类似区间dp的思想

逃离

题目传送门
乍一看没什么思路? 起点不固定?? 两条路径是分开来的??
其实不用管起点的问题,只要考虑当前这个点是哪个人正在收
两条路径分开来怎么办?? 其实我们不用在意,类似于传纸条的做法
我们令  f(i,j,k,0) 表示在  (i,j) 这个格子上,当前两个人收集量之差为  k ,是第一个人的方案数;  f(i,j,k,1) 同理,只是变成了第二个人而已

思想的类似

这种状态的思想和多米诺骨牌那道题差不多:
 n 个多米诺骨牌,每个骨牌可以旋转。问怎么在使上下两部分之和的差的情况下,旋转的次数最少
 f(i,j) 表示到第  i 个骨牌的时候,上面的和为  j 的最小旋转次数
 up[i]j 时,令  x=f(i1,jup[i])
 down[i]j 时,令  y=f(i1,jdown[i])+1
注:如果不满足条件的话,  x  y 的值等于
那么,转移方程就很简单了:

f(i,j)=min(x,y)

回归本题,那么剩下的就十分简单了
下面只写关于怎么求解  f(i,j,k,0)  f(i,j,k,1) 类似
设上一个人取完后的差为  x ,则  x=(k+num[i][j]))mod(K+1)
那么,我们可以得到以下转移方程:

f(i,j,k,0)=f(i,j,k,0)+f(i+1,j,x,1)+f(i,j+1,x,1)

求解  f(i,j,k,1) 的时候类似,只是此时当另外算出来的  x=0 的时候要加1
最后的答案即为 f(i,j,0,0)

时间复杂度?  O(n2k)
但是我还是离奇地爆了空间和时间……

电视节目

题目传送门
这很显然是一个树形结构,所以我们考虑树形dp
我们先令  f(i) 表示以  i 点的子树最大收益是多少
但是这似乎有一个问题:
可能当前收益为负数,但是和其他子树中和一下就变成正数了
所以这种dp是不可行的
那我们再考虑另一种思路:
我们令  f(i,j) 表示以  i 的子树,给  j 个用户的最大收益值
那么,最后的答案即为  k(f(1,k)0)
于是转移方程就可以得出来了:
 f(i,j)=max(f(i,jk)+f(soni,k)(i,soni).v)
转移时间复杂度是  O(n) 的,具体证明我在此不加赘述
如果转移时  j 的范围不注意的话,复杂度会严重退化
所以这边要注意一下:
 j 的范围为  [1,siz(i)]  siz(i) 表示  i 暂时访问到的那些儿子的子树中,有多少个叶节点,区别于  i 的子树大小
只有这样才会是  O(n)

棋盘制作

题目传送门
似乎并不是特别好做?
因为是黑白间隔,所以并不是特别好判断某一块是不是符合条件
那么,我们是不是要对这个矩阵做一个小小的处理??
先对这个矩阵黑白染色,然后将白格中的数取反
换句话说,如果行加上列为偶数的话,就把这个格子中的数取反
然后如果说一开始的某个矩阵是黑白相间的,例如01,那么这个矩阵经过处理后会变成元素全部相等的矩阵
所以我们就可以用单调栈求出最大的元素全部相等的矩形
正方形直接dp即可

正确性显然吧……
因为相邻的格子颜色必须不同,而判断间隔并不那么好判断,所以我们考虑取反,就比较方便了
具体的做法我就不加赘述了,时间复杂度  O(n2)

访问艺术馆

题目传送门
很经典的题目了吧
典型的树上背包问题
可能读入有点坑,递归读入即可
其实我们还可以边读入边dp……(我就这么干的)
注意:走廊也算成一个点
我们来讲讲怎么dp
很明显,我们令 f(i,j) 表示在 i 号点,还有 j 个单位时间内最多能偷多少画
转移应该比较显然的吧……

f(i,j)=max{f(l,k)+f(r,j2tk)}(0kj2t)f(i,j)=min((j2t)/5,pic)

第一种转移是当前点为走廊的时候,第二种是当前点为画馆的时候
应该还是比较直观的吧……

选课

题目传送门
因为这是一个森林,所以先将它并成一棵树,即0号点作为根
然后树形dp即可
这棵树是多叉树怎么办呢?
相对来说,我感觉多叉转二叉比较好,并且好写
啥意思? 就是把原本的儿子放在左子树,兄弟放在右子树
即变成了一棵二叉树
我们可以令 f(i,j) 表示以 i 为根的子树中,选择 j 门科目的最大总学分
那么,转移应该也蛮显然的

f(i,j)=max(f(r,j),f(l,k)+f(r,jk1)+vi)

理解起来应该没什么问题
这类树形dp问题应该属于比较简单的类型了吧
有些问题不能多叉转二叉……

奶牛聚集

题目传送门
此题是比较简单的树形dp题
我们可以设 f(i) 表示 i 子树内的距离和, g(i) 表示 i 子树外的距离和
然后转移自己推一推就行了
反正我写了2个dfs

你可能感兴趣的:(dp,区间dp,路径dp,树形dp,棋盘型dp)