DP习题笔记
循环的遍历
- 注意一下最内层的循环是什么,他决定了这一步的决策是什么。
例题
- 这一题要我们求完全背包的方案数(考虑顺序)
- 那么内层循环应该放的是面额的遍历,因为最后一步的面额是不一定的。
正确写法✔:
1
2
3
4for(int i=1;i<=w;i++)
for(int j=1;j<=n;j++)
if(i>=a[j])
dp[i]=(dp[i-a[j]]+dp[i])%mod;错误写法❌:
1
2
3
4
5
6for(int i=1;i<=n;i++){
ll x; cin>>x;
for(int j=x;j<=w;j++){
dp[j]=(dp[j-x]+dp[j])%mod;
}
}- 为什么下面那个是错误的?
- 因为把当前面额作为内层循环,相当于固定了最后一步只能是这个面额,没法考虑到顺序问题。这样的话第二次只能在第一次的基础上增加。实际上,第一次的面额也可以在第二次的基础上增加。因此这个做法是不正确的。
注意:下面那个方法因为只考虑了最开始的顺序(即输入顺序),所以只有一种顺序,那么就可以拿来统计组合数
在解决这类问题时,关键要问自己:
- 题目要求的是组合数还是排列数?
- 我的循环顺序是否允许不同的支付顺序?
- 我是否在无意中强加了某种顺序限制?(关键点)
对于这道题,既然要求考虑支付顺序,就必须使用金额在外层的循环方式。
特殊例题
计算容积不超过n得到的最大的占有体积
题目说可以双核,那么只要一边最接近sum/2就彳亍了,所以可以用上面那个模型
01背包0也有值的问题
在正常的01背包中,如果遍历不到就不管了,但是现在要求不能放入时也有一定的值,那么这时就要管了,在体积不够时,每一个都只有一种选法,那就是不选。所以每一个都要加上不选所对应的值。
例题:
- 题目说了在打不过时也能得到经验,你要是不给玩家经验,当然是不对的啦
DP的一般思路
- 首先看看是否是背包或者背包的变形,要是是的话就简单了
- 看一下每一次有几种转移方式,把可能的变化列一下,看看是否有规律
- 在这一讲还是不用区分特殊类型的DP的
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ZestfulYK的Blog!