P8806
搬砖
题目描述
这天,小明在搬砖。
他一共有 \(n\) 块砖,他发现第 \(i\) 砖的重量为 \(w_{i}\),价值为 \(v_{i}\)。他突然想从这些砖中选一些出来从下到上堆成一座塔,并且对于塔中的每一块砖来说,它上面所有砖的重量和不能超过它自身的价值。
他想知道这样堆成的塔的总价值(即塔中所有砖块的价值和)最大是多少。
输入格式
输入共 \(n+1\) 行, 第一行为一个正整数 \(n\), 表示砖块的数量。
后面 \(n\) 行, 每行两个正整数 \(w_{i}, v_{i}\) 分别表示每块砖的重量和价值。
输出格式
一行,一个整数表示答案。
样例 #1
样例输入 #1
5
4 4
1 1
5 2
5 5
4 3
样例输出 #1
10
提示
【样例说明】
选择第 \(1\)、\(2\)、\(4\) 块砖,从上到下按照 \(2\)、\(1\)、\(4\) 的顺序堆成一座塔,总价值为 \(4+1+5=10\)。
【评测用例规模与约定】
对于 \(20 \%\) 的数据,保证 \(n \leq 10\);
对于 \(100 \%\) 的数据,保证 \(n \leq 1000 ; w_{i} \leq 20 ; v_{i} \leq 20000\) 。
如果朴素做法的话 就是n次枚举哪个作为最下层 然后背包求解 O(wn^2) TLE
像这种题 一般都可以通过排序来确定最优序列的顺序 然后 只用一遍背包寻找最优满足要求的最优子序列即可
对于本题 按照 w+v 从小到大排序
排序推导依据: 任意y可以放x前面的情况,x都可以放y前面 这样将 x放在 y 前面的序列肯定是包含最优序列的
注意 我们用的是优化了一维的0/1背包 所以要倒序枚举j
CODE:
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct did {
int w,v;
} a[1005];
int f[40005];
int n,totw=0;
inline bool cmp(did x,did y) {
return x.w+x.v<y.w+y.v;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1; i<=n; i++)
cin>>a[i].w>>a[i].v,totw+=a[i].w;
f[0]=0;
sort(a+1,a+n+1,cmp);
for(int i=1; i<=n; i++)
for(int j=a[i].v; j>=0; j--) {
f[j+a[i].w]=max(f[j+a[i].w],f[j]+a[i].v);
}
int maxx=0;
for(int i=0; i<=totw; i++)maxx=max(maxx,f[i]);
cout<<maxx<<"\n";
return 0;
}

浙公网安备 33010602011771号