记录学习DP过程中的思想提升与总结
最优决策表=阶段+状态,一般使用数组表示,如f[i],f[i][j]。
当i的状态只与i-1的状态有关,可用滚动数组优化,i&1 ,(i-1)&1;
关于0/1背包为什么逆序枚举:
f [ 0 ~ v[i]-1 ] 处于第 i-1 个状态 ( 还没有第 i 个物品更新 )。
f [ v[i] ~ m ] 处于第 i 个状态(考虑过放入第 i 个物品的情况)。
倒序枚举 for ( int j = m ; j >= v[i] ; j - - )
f[0--------------------------------------,j]f[j,m]
i-1 i
f[0,-----------------------------j]f[j,---------m]
i-1 i
f[0,------------------j]f[j,--------------------m]
i-1 i
f[0,----------j]f[j,----------------------------m]
i-1 i
f[0,j]f[j,--------------------------------------m]
i-1 i
保证 i 是由 i-1 转移过来的。
关于动态规划中 阶段 状态 决策 三要素
1)阶段:将原问题划分成一个个类似的子问题,子问题的不同规模相当于不同阶段!
2)状态:枚举子问题中所有可能情况,表示所有可能状态。
3)决策:状态转移方程——选择某一状态中最优的解。
void dp()
{
for(int i=1;i<=n;i++)//前i个物品,将原问题的规模缩小
for(int j=m;j>=v[i];j++)//背包的所有可能状态
f[j]=max(f[j],f[j-v[i]]+w[i]);//状态转移方程
}
注意决策集合,在有些情况下,决策集合是只增多不减少的,所以可以保留之前的最优决策,不断与以后的决策比较,找到最优决策。
当划分状态时,一定要注意阶段状态的可转移性,即i状态必须能由i-1状态推出!
关于区间DP:
为什么第一重循环枚举区间长度?
这样可以保证计算大区间时小区间的值都在这之前计算出来了!当你计算 阶段/状态 转移的时候,一定要保证你用到的那些全部都已经被算出来了,比如区间dp,一般大区间的dp值由小区间算出来。