HDU 3466|Proud Merchants|01背包|贪心

题目

最近,iSea去了一个文明古国。很长一段时间内,这个国家是世界上最富有的而且还是最强大的国家。所以这个国家的公民拥有强烈的民族自豪感,即使国家不再富有了也不会丧失。
商人们是最典型的,每个商人仅仅出售一件物品,价格为 pi ,但是如果你的钱少于 qi ,商人就不会和你交♂易了。然后iSea认为物品的实际价值是 vi
如果iSea有M块钱,iSea能获得的最大价值是多少?

输入

输入包含多组数据。
对于每组数据,第一行2个整数 n,m(1n500,1m5000) ,表示物品的数目和iSea一开始有的钱。
接下来的n行,每行3个整数 pi,qi,vi(1piqi,1vi1000)
输入数据以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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值