题目描述
要点
1.每件物品只能使用一次
2.总体积不超过V
3.总价值最大
分析
按照集合划分
最后一个不选 i
代表要从 1 到 i - 1 中选择物品,并且其体积不超过j,这其实就是f[i - 1][j]
最后一个选 i
如果要选i的话,我们可以这么考虑,我们先把i的这个空给空出来,那么剩下的内容就变成从1到i - 1的物品中选择物品,并且其体积不超过 j - vi(这样就是把这个i的空空出来),其总价值的最大值为f[i - 1][j - v[i]],再把i的价值加上,就得到了最后一个选i这一类的最大值f[i - 1][j - v[i]] + w[i]
所以f[i][j] = max (f[i - 1][j], f[i - 1][j - v[i]]) + w[i]
二维写法
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 1010; int v[N]; //体积 int w[N]; //价值 int f[N][N]; //f[i][j],j体积下前i个物品的最大价值 int main() { int n, m; 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 ++) { if (j < v[i]) f[i][j] = f[i - 1][j]; else f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]); } printf ("%d\n", f[n][m]); return 0; }
在上面的代码里我们可以看到
f[i][j] = f[i - 1][j]; if(j >= v[i]) f[i][j] = max(f[i][j],f[i - 1][j - v[i]] + w[i]);
这里,推导f[i][j]的时候,我们只用到了f[i - 1]这一层的信息,所以我们可以使用滚动数组将需要用到的信息存到一维数组中。所谓滚动数组,其实也就是我计算第 i 层的数据时,使用滚动数组的内容(就是i - 1层的数据),当我计算完之后,我的数据就存进滚动数组中,这样计算 i + 1 层的时候,就可以继续使用第 i 层的数据。
为何逆序
数组中元素不可重复使用
一维写法
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 1010; int v[N], w[N]; int f[N]; int main() { int n, m; 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 = m; j >= v[i]; j --) f[j] = max(f[j], f[j - v[i]] + w[i]); printf ("%d\n", f[m]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix