数组表示一个集合,表示的值是集合的一个特性(可以自己定),每一个集合都有几个限制条件,求出的值必须满足这个特性。转移方程的推导可以看做是把一个集合划分成几个不同的子集,这些子集的特性是已知的,就可以转移。
1.状态表示:集合、属性
2.状态转移:划分集合
重要思想:
每个子问题的决策不能被后面其他未解决的问题影响
某阶段的状态一旦确定,则此后过程的演变不再受此前各种状态及决策的影响
某阶段的状态一旦确定,未来的决策不会再影响前面的
未来的决策不会受到前面的影响(只能直接调用结果) ,也不会影响前面的决策
注意问题:
1.每一个存在和合理的状态的值都必须存在,且值必须是正确的。如果有一个状态不合理,必须和所求的属性赋值一个极大的相反值
2.如果发现当前维数的状态方程难以推导,可以考虑再开一维
3.分组背包的理解:分组背包就是把01背包的for循环顺序交换了一下,理解:交换之后,先枚举组数,然后枚举体积,在体积里面枚举每一组的物品,所以,在更新一个体积的时候,就只会用这一个组内,能使当前结果最优的一个进行更新,就可以实现,一组只取一个的目的。
4.如果从一个集合要推出当前这个集合的话,就必须明确他们之间元素的关系,如果不能确定,南无状态转移方程几有可能推错了,需要重新从一个确定的状态转移。集合之间
5.有的背包里面,时间可以使价值也同时可以使体积
6.顺推和倒推的最优子结构满足性区别,(顺推)它以前各阶段的状态无法直接影响它未来的决
策,所以,如果有延后性的满足条件,我们就可以倒推来解决这个问题
6.最长上升子序列可以开一个数组记录一下过程,记录一下过程中的分数之和
7.有多种情况组合而成的时候,可以把这些情况拆解开,分成多个分别dp,再找出他们之间的关系
8.矩阵求的dp有很多,一般都是拆解开,分多个dp
9.依赖背包(树形)就是分组背包的变形,是枚举分给每一个子树多少体积,这相当于分组背包里,一个组里的一个物品,一个物品当然不能被选两遍,所以,一个子树的一种体积状态也不能被更新两次。但是,这个子树的每一种体积的状态枚举和顺序是无关的。由此我们可以得出,外层枚举体积的循环要倒序,但是内层枚举每一个子树的体积的时候,不用在乎顺序的问题(和分组背包一样),都是要求当前体积下,一种子树体积去更新局部最优解。
10.注意,不成立的状态,不可能的状态,如果存在后面会转移的可能性,就要把它的值设为与答案完全相反的一个值,防止用这个值更新出一种不成立的最值答案。
11.dp的时候,该开long long就开long long不要吝啬,否则就会爆0,但是有的时候,看题上的空间限制,如果开得太多,也会爆0,
12.dp的转移方程其实不难,基本都可以自己推出来。
13.有的题目上的物品并不是真正的物品,可能转化为(一艘船),用看似不想关联的事物做每一个单独的物品
14.注意考虑最差情况的转移,并非只有最好的情况可以转移(可能最好的情况不合法)
15.注意差值bool的动态规划,表示一种状态可不可行
16.动态规划还可以使用倍增的思路,比较简单一些,就和lca一样,把一种状态的2^0的状态预处理一下,然后就可以使用倍增快速处理出数据,
17.如果有两个元素之间的关系,可以开两个数组,分别作第一关键字和第二关键字,这样dp就有了转移的可能
18.区间dp就是先枚举区间长度,枚举左端点,再枚举断点,注意断点的定义,正不能把一个l,r枚举两次 。如果k是包括k算在左侧区间的话,结尾就是<r,反之,就是从l+1开始枚举。假设两边都包含,那样就会把l,r算两次,而且,值还会被加两次
19.区间dp在赋初值的时候,看清楚初值和代价的区别,若把代价赋成初始值,就会算两遍len==1的初始值,
20.排列问题可以考虑插入后的状态变化(一般是有序插入)
21.对dp无后效性的理解:就是在dp的时候必须要满足最优子结构,满足之后,在下一次决策时可以调用当前的最大值进行转移,可以知道,这种一定是最大的情况。无后效性就是指,如果当前决策的最优性会受到以后决策的影响,那么,就不可能进行状态转移,所以设计一个结构,使决策的性质只会在两次之间传递,只会和前一个有影响,或者是能推出来下一个,那么,转移就是有可能的
21.动态规划中的压缩路径问题,压缩路径优化数组, t * ( t - 1)就是路径,可以看做不论怎样走,都可以先走一段,然后具体走
22.动态规划主要还是看清题目上给的限制条件,用限制条件卡循环范围和转移方程
23.有返回值的函数如果不写retrun就会奇妙!!!!
24.(dp自己一个小时推出来的感觉简直不要太爽)
25.数组赋初始值极大值或者极小值的时候,尽量在for内部赋值,这样就会防止一些本应该是0的状态被memset改变
26.dp输出方案可以使用贪心的思想,只要是可行解就行
27.在进行背包的时候,有时会发现背包的体积太大,物品的体积也很大,我们就可以把每一件物品减去 mi - 1 ( mi 是物品中的最小体积),把总体积设为sv(物品的总体积 - n*mi),然后开二维的背包,三重for循环,只要判断一下j + k*mi<= w就可以
28.可以用pair来保存下标,然后记录转移就可以很方便
29.字符串区间染色的问题可以用区间dp来做
30.其实有的题目中判断情况成不成立可以转化为非常简单的问题,比如区间满覆盖
31.dp的有些问题也可以使用贪心的思想
32.dp方程的初始化最好是赋为极值,因为你不知道哪个不合法的状态会转移东西,比如f[0][5]