第五章 动态规划
动态规划问题是没有模板的,比较像数学,代码非常简单,都是一些循环,它核心的地方在于状态的表示和状态的转移,比较偏数学,包括贪心一章也是,是没有模板的。
动态规划的时间复杂度一般是:状态数量 * 转移的计算量
思考状态表示的维数,在能够算出答案的基础上,维数越小越好,每多一维,意味着时间复杂度就多一倍,所以会从小到大来思考维数,先考虑一维,不行再二维,不行再三维……。
动态规划就是要多想,多尝试,和做数学题一样 ,想第一种方法能不能做,不行就第二种,……
一、背包问题
给 n 个物品,和一个容量为 v 的背包,每个物品有两个属性,它的体积 vi,它的价格(权重)wi。
DP优化:一般来说都是对DP的代码,或者DP的方程,做一个等价变形
所有DP问题,都可以用以下方式来思考:
DP问题一般是用来求:最大值、最小值、数量。
那么数组中的值就是上述所求的值。
1、01背包
每种物品仅有一件,可以选择放或不放,01背包问题的由来
用子问题定义状态:即f[i][v]表示前i件物品放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
f[i][v]=max{ f[i-1][v], f[i-1][v-w[i]]+c[i] }
所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。
如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”。
如果放第i件物品,那么问题就转化为 “前i-1件物品放入剩下的容量为:v-w[i]的背包中” ,此时能获得的最大价值就是f[i-1][v-w[i]]再加上通过放入第i件物品获得的价值c[i]。
2、完全背包
每件物品有无限次
属性:(Max)
去掉 k 个 i
求 Max,f[ i - 1, j - k * v[i] ]
加上k个i
f[i, j] = max( f[i - 1, j - v[i] * k] + w[i] * k ) ;
3、多重背包
每件物品能用无限次
4、分组背包
二、线性DP
1、数字三角形
从上到下或者从下到上都可以,上到下计算量更大一些,走过每一个点,都会计算其中的最大值,所以计算上方和右上两个点中的最大值就行。
2、最长上升子序列Ⅰ
遍历前方,找到比当前值小的最长上升子序列,然后+1。
如果想把最长序列保存下来,可以借用数组模拟链表的思想,g[i] 存储第 i 个值的前一个序列。
3、最长公共子序列
f[i][j] 表示 在第一个字符串的前 i 个字符 与 第二个字符串的前 j 个字符串的最大子序列
只有有四种情况,
00 表示最大子序列中不包含 i j,
01 表示不包含 i,包含j
10 表示包含 i,不包含j
11 表示包含 i j
00 是不用计算的,因为结果一定包含在 01 和 10 里面,我们做的时候也不会直接判断 i j
三、区间DP
就是在定义状态,是定义了一个区间