一、引言
完全背包,即所有物品都无限制数量的拿取,则可以使用三层循环,而三层循环的大样例基本都会爆时间,那么应该怎么省时间呢?
二、分析
朴素完全背包可以使用三层循环,最后一层循环即为每件物品的数量
那么状态转移方程即如下:
但是能不能像01背包一样用二层循环呢?
我们通过列举一件物品的每一个数量可以发现每次的都是在两边添加w[i]
所以最终的状态转移方程可以写为这样:
再将其优化成一维滚动数组,就完成了时间与空间的双优化
三、完整代码
#include<iostream>
using namespace std;
const int N = 1e3 + 5;
int dp[N], w[N], v[N]; //分别是dp数组、价格数组和容量数组
int m, n;
int main(){
scanf("%d%d", &m, &n); //m表示物品数量,n表示背包总容量
for(int i = 1; i <= m; i++){ //从1开始存,避免减一超范围
scanf("%d%d", &w[i], &v[i]); //每件物品的价格与容量
}
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){ //完全背包不用倒叙遍历
// 不选则保存上一行的,所以不用变
if(j >= v[i]){ //如果背包容量可以装下这个物品
dp[j] = max(dp[j], dp[j-v[i]] + w[i]); //就从选这个物品和不选这个物品中挑一个价值更大的
}
}
}
printf("%d", dp[n]);
}