接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式 输出一个整数,表示最大价值。
数据范围 0 0
4 5
1 2 3
2 4 1
3 4 3
4 5 2
1
2
3
4
5
输出样例:
输出样例:
10
1
思想
状态表示:
集合:dp[i][j]表示前i个物品,总体积不超过j的价值
属性:最大价值
状态计算:
不选第i个 物品:dp[i][j] = dp[i - 1][j]
选第i个物品k个:dp[i][j] = dp[i - 1][j - k * v[i]] + k * w[i]
集合属性为最大价值,故两种情况取max()
当背包容量不够或者物品数量不够时,即j < k * v[i] || k > s[i]时,不能选择物品,反之可选
代码
#includeusingnamespace std;constint N =1e3+10;int dp[N][N];int v[N], w[N], s[N];voidsolve(){int n, m;
cin >> n >>m;for(int i =1; i <= n; i ++) cin >> v[i]>> w[i]>> s[i];for(int i =1; i <= n; i ++){for(int j =1; j <= m; j ++){for(int k =0; k * v[i]<= j && k <= s[i]; k ++){//枚举选择物品的个数
dp[i][j]=max(dp[i][j],dp[i -1][j - k * v[i]]+ k * w[i]);}}}
cout << dp[n][m]<< endl;}intmain(){solve();return0;}
由拆分出的这些新的捆绑物品,我们可以凑出
1
∼
s
[
i
]
1\sim s[i]
1∼s[i]之间的任意数目的i物品,不必逐一枚举进行选择
由二进制拆分,原有的每个物品数量
S
S
S可以降为
l
o
g
2
S
log_2^S
log2S,时间复杂度大幅降低
对于最终求解,可以采用01背包的一维优化求解
代码
#includeusingnamespace std;constint N =1e6+10;int dp[N];int cnt;//用于记录新的捆绑物品的下标int v[N], w[N];voidsolve(){int n, m;
cin >> n >> m;for(int i =1; i <= n; i ++){int a, b, s;
cin >> a >> b >> s;int k =1;//k从1开始捆绑while(k < s){
cnt ++;
v[cnt]= k * a;//捆绑物品的体积
w[cnt]= k * b;//捆绑物品的价值
s -= k;
k <<=1;}if(s){//最后剩余的无法凑整的数
cnt ++;
v[cnt]= s * a;
w[cnt]= s * b;}}for(int i =1; i <= cnt; i ++){//01背包一维优化求解for(int j = m; j >= v[i]; j --){
dp[j]=max(dp[j],dp[j - v[i]]+ w[i]);}}
cout << dp[m]<< endl;}intmain(){solve();return0;}