problem
luogu
你有 nnn 个箱子,编号从 1 到 n,每个箱子有三个属性,以第 iii 个箱子为例,分别是重量 wiw_iwi,承重能力 sis_isi,价值 viv_ivi。
你想建一座塔,因此需要将一些箱子堆叠起来,但是每个箱子必须满足下面的条件:
- 这个箱子上面的所有箱子重量和要小于这个箱子的承重能力。
定义一个塔的价值为它所用的所有箱子的价值和。
最大化这个塔的价值并输出它。
solution
这种前后两个顺序有优劣差别,但不会影响除两个物品外的其余物品,每个物品具有多个属性的题目。
往往需要进行局部最优性的属性排序,然后再做一遍背包即可。
这里考虑相邻的两个物品 i,ji,ji,j。
设前面物品的总重量为 WWW,显然这两个的顺序不会影响后面物品的摆放。
假设 iii 必须放在 jjj 前面才行。
则有 W+wj≤si∧sj<W+wiW+w_j\le s_i\wedge s_j<W+w_iW+wj≤si∧sj<W+wi,两式相加有 wj+sj<wi+siw_j+s_j<w_i+s_iwj+sj<wi+si。
所以将所有物品按 s+ws+ws+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;
}