problem
你有 n n n 个箱子,编号从 1 到 n,每个箱子有三个属性,以第 i i i 个箱子为例,分别是重量 w i w_i wi,承重能力 s i s_i si,价值 v i v_i vi。
你想建一座塔,因此需要将一些箱子堆叠起来,但是每个箱子必须满足下面的条件:
- 这个箱子上面的所有箱子重量和要小于这个箱子的承重能力。
定义一个塔的价值为它所用的所有箱子的价值和。
最大化这个塔的价值并输出它。
solution
这种前后两个顺序有优劣差别,但不会影响除两个物品外的其余物品,每个物品具有多个属性的题目。
往往需要进行局部最优性的属性排序,然后再做一遍背包即可。
这里考虑相邻的两个物品 i , j i,j i,j。
设前面物品的总重量为 W W W,显然这两个的顺序不会影响后面物品的摆放。
假设 i i i 必须放在 j j j 前面才行。
则有 W + w j ≤ s i ∧ s j < W + w i W+w_j\le s_i\wedge s_j<W+w_i W+wj≤si∧sj<W+wi,两式相加有 w j + s j < w i + s i w_j+s_j<w_i+s_i wj+sj<wi+si。
所以将所有物品按 s + w s+w s+w 排序后做一遍背包即可。
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
int f[1005][20005];
int n;
struct node { int w, s, v; }it[1005];
signed main() {
scanf( "%lld", &n );
for( int i = 1;i <= n;i ++ )
scanf( "%lld %lld %lld", &it[i].w, &it[i].s, &it[i].v );
sort( it + 1, it + n + 1, [](node x, node y ){ return x.w + x.s < y.w + y.s; } );
for( int i = 1;i <= n;i ++ )
for( int j = 0;j <= 2e4;j ++ ) {
if( j <= it[i].s )
f[i + 1][j + it[i].w] = max( f[i + 1][j + it[i].w], f[i][j] + it[i].v );
f[i + 1][j] = max( f[i + 1][j], f[i][j] );
}
int ans = 0;
for( int i = 0;i <= 2e4;i ++ ) ans = max( ans, f[n + 1][i] );
printf( "%lld\n", ans );
return 0;
}