题目
最近,iSea去了一个文明古国。很长一段时间内,这个国家是世界上最富有的而且还是最强大的国家。所以这个国家的公民拥有强烈的民族自豪感,即使国家不再富有了也不会丧失。
商人们是最典型的,每个商人仅仅出售一件物品,价格为
pi
,但是如果你的钱少于
qi
,商人就不会和你交♂易了。然后iSea认为物品的实际价值是
vi
。
如果iSea有M块钱,iSea能获得的最大价值是多少?
输入
输入包含多组数据。
对于每组数据,第一行2个整数
n,m(1≤n≤500,1≤m≤5000)
,表示物品的数目和iSea一开始有的钱。
接下来的n行,每行3个整数
pi,qi,vi(1≤pi≤qi,1≤vi≤1000)
。
输入数据以EOF结束。
输出
对于每个测试数据,输出一行一个整数,表示iSea能获得的最大价值。
样例输入
2 10
10 15 10
5 10 5
3 10
5 10 5
3 5 6
2 7 3
样例输出
5
11
题解
首先可以联想到01背包。对于条件如果钱少于
qi
就不交易了,只需要把枚举背包质量下界从
pi
改成
qi
即可。但是,这样做会有问题。
我们看第二个样例,如果我们先处理第一个物品,就会有dp[10]=max(dp[10], dp[5] + 5)
,然后我们处理第二个物品:dp[5..10]=max(dp[5..10], dp[2..7] + 6)
,我们发现,按照这个顺序处理物品,dp[10]先表示选第一个物品,后表示选第二个物品,但始终没有表示既选第一个,又选第二个的情况。
实际上我们有选物品的顺序,显然我们只能先选第一个物品,再选第二个物品,这是一个钱变少的过程。但是背包问题我们考虑的是背包质量越来越大的过程,考虑的顺序是相反的,所以我们处理物品的顺序也要反过来,按照q-p从小到大排序做01背包就可以了(显然先满足q-p比较大的物品)。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,j,k) for(i=j;i<k;++i)
using namespace std;
struct Item {
int p, q, v;
bool operator< (const Item &b) const {
return q - p < b.q - b.p;
}
} a[505];
int dp[5005];
int main() {
int n, m, i, j;
while (scanf("%d%d", &n, &m) != EOF) {
memset(dp, 0, sizeof dp);
rep(i,0,n) scanf("%d%d%d", &a[i].p, &a[i].q, &a[i].v);
sort(a, a + n);
rep(i,0,n)
for (j = m; j >= a[i].q; --j)
dp[j] = max(dp[j], dp[j - a[i].p] + a[i].v);
printf("%d\n", dp[m]);
}
return 0;
}