完全背包:
在N种物品中选取若干件(同一种物品可多次选取),放在体积为V的背包里,每种物品的体积为w1,w2......wn,与之相对应的价值为v1,v2......vn,求解怎么装物品可使背包里物品总价值最大?
动态规划:
dp[i][j]表示前i种物品中选取若干件物品放入体积为j的背包中所能得到的最大价值。
状态转移方程:
dp[i][j] = max(dp[ i - 1 ][ j - k * w[i] ] + k * v[i]),0 <= k * w[i] <= j
其中dp[ i - 1 ][ j - k * w[i] ] + k * v[i]表示从前i-1种物品中选取若干件物品放入体积为j - k * w[i]的背包中所能得到的最大价值加上k件第i种物品的价值。
如果直接按照此状态转移方程进行dp,会有三层循环,复杂度为O(NV∑(j/w[i])),可以基于01背包的思想进行多个优化,最后的复杂度为O(NV)。
实现:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[10000];
int w[100],v[100];//体积 价值
int main(){
int N,V;
memset(dp,0,sizeof(dp));
scanf("%d%d",&N,&V);
for(int i = 1;i <= N;i++){
scanf("%d%d",&w[i],&v[i]);
}
for(int i = 1;i <= N;i++){
for(int j = w[i];j <= V;j++){
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
}
}
return 0;
}
优化一:采用一维数组,空间复杂度更低。不同于01背包的是,01背包采用一维数组体积需要逆序,而此处为顺序。原因是可以重复放置物品。
优化二:减少了枚举k这层循环,时间复杂度更低。不用去枚举k,原因是,当去顺序枚举体积,已经隐含着某类物品可以放多个。