完全背包问题——动态规划
完全背包问题
-
问题描述:
有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
第 i 种物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
-
动态规划解法:
设F[i][j]表示只看前i个物品,总体积是j的情况下,总价值是多少(与0~1背包表示意义一样)。先做出如下推导:
在计算状态i,j的值F[i][j]时,即在体积不超过j的情况下选择第i件物品时,除了要考虑前一状态F[i-1][j](在j的情况下只考虑前i-1件物品)外,还要考虑放置1件i物品、放置2件i物品·····放置k件i物品、直至放满为止这一类大情况。故结果有:
F[i][j] = max(f[i-1][j], f[i-1][j-v] + w, ····, f[i-1][j-kv] + kw) 1
据此另外可以推得如下:
F[i][j-v] = max(f[i-1][j-v], f[i-1][j-2v] + w, ····, f[i-1][j-(k+1)v] + kw) 2
仔细观察1、2式可得,1中max内的右半部分比2式多出一个w,故可用2式+w来代替。即F[i][j] = max(f[i-1][j], f[i][j-v] + w);
-
代码示例:
#include<bits/stdc++.h> using namespace std; const int N = 1010; int f[N][N], n, m, v[N], w[N]; int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) scanf("%d%d", 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]); } printf("%d", f[n][m]); return 0; } -
优化后:(优化后在具体理解方式上还是要按照二维数组的思路来)
#include<bits/stdc++.h> using namespace std; const int N = 1010; int f[N], n, m, v[N], w[N]; int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) scanf("%d%d", 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]); printf("%d", f[m]); return 0; } -
0~1背包与完全背包对比:
0~1背包:取左边状态和左上(不严格左上)状态的最大值。
完全背包:取左边状态和正上面(不一定相邻的上面)状态的最大值。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix