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;
}
posted @ 2023-03-25 12:54  N0zoM1z0  阅读(38)  评论(0)    收藏  举报