背包 dp 学习笔记
01背包
题面
有
思路
定义
由此我们可以讨论取或不取,推出转移方程。
由于对
需要注意的是,枚举时需要倒序枚举,才能保证物品只能使用一次,顺序则为完全背包做法。
for(int i=1;i<=n;i++)
{
for(int j=m;j>=w[i];j--)//倒序枚举
{
dp[j]=max(dp[j],dp[j-w[i]]);
}
}
完全背包
题面
有
思路
根据 01 背包,我们不难想出正序枚举即可实现物品使用多次。用
for(int i=1;i<=n;i++)
{
for(int j=w[i];j<=m;j++)//正序枚举
{
dp[j]=max(dp[j],dp[j-w[i]]);
}
}
多重背包
题面
有
暴力思路
容易想到,把「每个物品拆成
转移方程即为
单调队列优化
我们在暴力思路上容易观察对于每一个
那我们不妨跳着计算
既然余数统一,形式就可以表示成
固定长度的区间最大值,即可用单调队列来实现。
有一个小细节就是队列里存的是
具体细节见代码。
for(int i=1;i<=n;i++,b^=1)//滚动数组
{
for(int r=0;r<v[i];r++)//固定余数
{
while(!q.empty()) q.pop_back();//清空队列
for(int k=0;k<=m/v[i];k++)
{
while(!q.empty()&&q.front()<k-c[i]) q.pop_front();//弹队首
while(!q.empty()&&dp[b^1][r+q.back()*v[i]]+(k-q.back())*w[i]<dp[b^1][r+k*v[i]]) q.pop_back();//维护队列递减性,注意是 b^1
q.push_back(k);
dp[b][r+k*v[i]]=(dp[b^1][r+q.front()*v[i]]+(k-q.front())*w[i]);//更新答案
}
}
}
分组背包
题面
有
思路
这道题其实和 01 背包非常的相似,其实是从「在所有物品中选择一件」变成了「从当前组中选择一件」,于是就对每一组进行一次 01 背包就可以了。
注意循环顺序,才能保证答案正确性。
for (int k = 1; k <= zs; k++)//循环每一组
for (int i = m; i >= 0; i--)//循环背包容量
for (int j = 1; j <= cnt[k]; j++)//循环该组的每一个物品
if (i >= w[z[k][j]])
dp[i] = max(dp[i],dp[i - w[z[k][j]]] + c[z[k][j]]);//像 01 背包一样状态转移
求字典序最小方案
题面
有
第
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是
思路
在背包求解的基础上,新建一个数组记录是「从哪一个转移过来」的就行了,注意不能压维,不然无法判断具体是从哪一个转移过来的。
要倒着枚举,保证字典序最小。
for(int i=n;i>=1;i--)
{
for(int j=0;j<v[i];j++)
{
dp[i][j]=dp[i+1][j];
path[i][j]=path[i+1][j];
}
for(int j=v[i];j<=m;j++)
{
if(dp[i+1][j]>dp[i+1][j-v[i]]+w[i])//注意如果相等尽可能取当前数
{
dp[i][j]=dp[i+1][j];
path[i][j]=path[i+1][j];
}
else//因为倒着枚举,当前数字典序更小
{
dp[i][j]=dp[i+1][j-v[i]]+w[i];
path[i][j]=i;
}
}
cout<<dp[1][m]<<" ";
int x=path[1][m];
s.push(x);
m-=v[x];
do{
x=path[x+1][m];
m-=v[x];
s.push(x);
}while(path[x+1][m]);
cout<<s.size()<<"\n";
while(!s.empty())
{
cout<<s.front()<<" ";
s.pop();
}
本文作者:yaaaaaan
本文链接:https://www.cnblogs.com/yaaaaaan/p/18605625
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步