最近在ICPC备赛,背包DP对于我来说一直都是难点,今天看到几个博文写的挺好的,在此转载一下
01背包
(每个物体只能拿一次,要求在一定的空间内,拿物体使得到的价值最大)
有两种写法,一种是二维数组,一种是一维数组(省空间)
1.二维dp的模板
状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-wei[i]]+val[i]);
基本操作:
if(j>=wei[i])
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-wei[i]]+val[i]);//i为面对第几个物体了
//j为所占的空间大小下,dp数组存的是对应的价值
}
else//这种写二维的方式可不清空
{
dp[i][j]=dp[i-1][j];
}
2.一维dp模版
状态转移方程:dp[j]=max(dp[j],dp[j-wei[i]]+val[i]);
基本操作:
memset(dp,0,sizeof(dp));//一维记得清空
for(int i=1;i<=n;++i)
{
for(int j=v;j>=wei[i];--j)
{
dp[j]=max(dp[j],dp[j-wei[i]]+val[i]);
}
}
cout<<dp[v]<<endl;
总结:简单来说就是对于每一个物体有两种选择,要么拿要么不拿,如不拿就继承上一个状态,否则就上一个状态的dp的值加上当前物体的价值。
二:完全背包问题
(每个物体可以拿无数次,要求在一定的空间内,拿物体使得到的价值最大)
板子:
状态转移方程:dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
基本操作:
for(i=1;i<=n;i++)
for(j=w[i];j<=m;j++) //注意此处与01背包不同,01为倒序
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
优化:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。
三、多重背包问题
(每个物体最多可以拿c【i】次,即次数限制可能不同。要求在一定的空间内,拿物体使得到的价值最大)
板子:(该板子参考:https://blog.csdn.net/qq_41117236/article/details/80986564)
状态转移方程:dp[j]=MAX{dp[j],dp[j-kw[i]]+kv[i]};
基本操作:
for(i=1;i<=n;i++)
for(j=m;j>=0;j--)
for(k=0;k<=c[i];k++)
{
if(j-k*w[i]<0) break;
dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]);
}
转载声明:本文为CSDN博主「suheyin」的原创文章
原文链接:https://blog.csdn.net/suheyin/article/details/86485399