虽然上一篇文章说了完结了,但经过高人指点,还需要出个第三期
言归正传
首先,我们先来说说易错点
总结了以下几点:
子问题重叠性,在使用min或max时,要根据题目决定是否将目前的状态假如,此易错点在上一篇文章已经说过,大家可以回看一下
数组的下标,我们正常使用c++都是从1开始,但是数组的开始是0.
初始化,有时不能简单的初始化为0,有时需要最大化,有时需要特殊值。而且f[0]这个位置也要考虑到
for循环边界,有的题就是简单的1-n等等,到有的初始值不一样,所以要格外注意
就是数组大小,题目中也许有多个数,但是数组的大小一定要注意,有时就会爆了
本蒟蒻找的易错点就是这些,如果还有其他的,请各位佬评论区为蒟蒻补充(doge)
现在来说说经典例题
上次说的斐波那契就不讲了
开心的金明(P1060)
因为字体不是正规的,全都是问号,所以就上截屏了
输入输出样例
输入 #1
1000 5
800 2
400 5
300 5
400 3
200 2
输出 #1
3900
如果你刷了很多的动态规划题,你就会发现
金明的事儿真的好多真的很好
这道题属于是01背包题
01背包是啥?
不错我前面确实没讲给忘了
01背包就是n个物品,每个物品可能会有价值和价格
但是只有m元钱,问能达到最大价值,这里的最大价值有时不光是相加,因题而异
思想:
每个物品有两种情况:
买
不买
状态定义:f[i]代表i元钱能买的最大价值
初始化:w[i]*=v[i](价值算法,见题目)
状态转移方程:
重中之重
两层循环,i从1到n代表n个物品,j从1到v[i],遍历花多少钱
f[j]=max(f[j],f[j-v[i]]+w[i])
f[j-v[i]]代表买第j个物品之前的最大价值,买完后加上第j个价值
AC代码:
#include<iostream>
#include<algorithm>
using namespace std;
int w[30],v[30],f[50000];
int n,m;
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
w[i]*=v[i];
}
for(int i=1;i<=n;i++){
for(int j=m;j>=v[i];j--){
if(j>=v[i]){
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
}
cout<<f[m]<<endl;
return 0;
}
今天的动态规划讲解到这里就结束了
出不出(4)现在说不准()