问题描述:
基本思路:
这个问题和 01背包 问题非常的相似,只是 01背包 问题要求了每个物品我们最多可以选一次(选和不选两种选择),但是完全背包问题只要容量够我们可以无限制的选
如果我们依然采取和 01背包 一样的状态的定义
dp[i][j] 代表 前 i 个物品 容量为 j 的时候的最大价值
那么状态转移方程也就出来了:
dp[i][j] = max(dp[i][j],dp[i][j-k*v[i]]+w[i]);
int dp[1010][1010]; int v[1010],w[1010]; int main() { int n,m; std::cin >> n >> m; for (int i = 1;i <= n;i++) { std::cin >> v[i] >> w[i]; } for (int i = 1;i <= n;i++) { for (int j = 0;j <= m;j++) {for (int k = 0;k * v[i] <= j;k++) { dp[i][j] = std::max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]); } } } std::cout << dp[n][m] << std::endl; return 0; }
但是稍微分析一下这个算法的时间复杂度 和 空间复杂度都是比较高的
我们可以采取和之前 01背包 一样的优化方法去优化一下
简单的优化:
之前讲 01背包 采取滚动数组的方法去优化必须要从大往小更新,这是因为我们每次都是要之前的状态
但是 完全背包 的话我们可以看作他是在 01背包的基础上取了之后再继续取,所以我们每次都是在更新之后的状态上进行更新,也就是我们要从小往大更新
这样这个算法的复杂度就变成了 O(N * M)
int dp[1010]; int main() { int n,m; std::cin >> n >> m; for (int i = 1;i <= n;i++) { int v,w; std::cin >> v >> w; for (int j = v;j <= m;j++) dp[j] = std::max(dp[j],dp[j-v]+w); } std::cout << dp[m] << std::endl; return 0; }
来源:https://www.cnblogs.com/-Ackerman/p/12250260.html