背包
一》01背包
简单来说就是给你一个有可容m重的背包,然后给你一组物品的价值和重量,让你将这些物品装进背包使价值最大,物品只能拿一次(也就是每种物品只有一个)
01背包模板
for(int i=n;i>=1;i--){
for(int j=m;j>=v[i];j--){
if(dp[j-v[i]]+v[i]>dp[j]){
dp[j]=dp[j-v[i]]+v[i];
}
}
}
二》多重背包
简单来说就是相对01背包每种物品有多个,所以多重背包其实可以通过某些手段变成01背包来写,也就是那种多个物品拆开成种,可以用二分拆分
for(int i=1;i<=n;i++){
scanf("%d %d %d", &w[i], &v[i], &mm[i]);//读入物品重量价值和数量
for(int j=1;j<=mm[i];j*=2){//二分拆开
nn++;
nw[nn]=j*w[i];
nv[nn]=j*v[i];
mm[i]-=j;
}
if(mm[i]>0){//多的另放
nn++;
nw[nn]=mm[i]*w[i];
nv[nn]=mm[i]*v[i];
}
}
for(int i=1;i<=nn;i++){//01背包跑一遍
for(int j=m;j>=nw[i];j--){
if(j>=nw[i])dp[j]=max(dp[j], dp[j-nw[i]]+nv[i]);
}
}
三》完全背包
有n种重量和价值分别为w和v的物品。有一个容重量为W的背包。求出背包能装下的最大价值,每种物品的数量是无限的。
for(int i=1; i<=n; i++)
for(int j=1; j<=W; j++)
{
dp[i][j]=-1;
for(int k=0; k*w[i]<=j; k++)
dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
}
总结
感觉就是dp的单方向拓展,重点在于找状态转移方程,背包实行的时候注意背包类型,完全背包不能反着跑,会出现错误。定义数组的时候看好范围,不要定小,也不要定太大(不然初始化的时候会tle)。模板都挺简单的,主要是会在题目中应用。