AcWing 3. 完全背包问题
题面:
有种物品和一个容量是 的背包,每种物品都有无限件可用。
第种物品的体积是 ,价值是 。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
原题链接:3. 完全背包问题 - AcWing
根据01背包的思路扩展到完全背包:
- 01背包:建立集合,对于第
种物品来说,有选
/不选
两种选择; - 完全背包:建立集合,对于第
种物品来说,有选0件(不选)
/选1件
/选2件
/……/选k件
/……
共 种选择。
- 完全背包-状态转移方程:
- 推导过程:
- 01背包-状态转移方程:
; - 完全背包-朴素方程:
; - 等价变形:
;
- 01背包-状态转移方程:
#include <bits/stdc++.h> using namespace std; const int N = 1010; int v[N], w[N]; int f[N][N]; int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) cin >> v[i] >> w[i]; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { f[i][j] = f[i - 1][j]; if (j >= v[i]) f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]); } } cout << f[n][m]; }
二次优化降维
- 01背包优化:从大到小枚举体积;
①确保在计算 时, 已经被更新过:
②保证每个物品仅被添加一次。 - 完全背包优化:从小到大枚举体积;
因为当背包容积较小时,右侧集合不一定存在。
与01背包的区别:01背包每样物品只能选择一次,所以状态只能从上一行转移;而完全背包的状态可以从本行转移(即 ),所以需要正向枚举。
#include <bits/stdc++.h> using namespace std; const int N = 1010; int v[N], w[N], f[N]; int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) cin >> v[i] >> w[i]; for (int i = 1; i <= n; i++) for (int j = v[i]; j <= m; j++) f[j] = max(f[j], f[j - v[i]] + w[i]); cout << f[m]; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!