HDU 3466 Proud Merchants(背包变式:贪心排序,01背包优化,背包的无后效性)2021-08-10

Problem
Proud Merchants Recently, iSea went to an ancient country. For such a long time, it was the most wealthy and powerful kingdom in the world.
As a result, the people in this country are still very proud even if their nation hasn’t been so wealthy any more. The merchants were the most typical, each of them only sold exactly one item, the price was Pi, but they would refuse to make a trade with you if your money were less than Qi, and iSea evaluated every item a value Vi. If he had M units of money, what’s the maximum value iSea could get?

Input
There are several test cases in the input.

Each test case begin with two integers N, M (1 ≤ N ≤ 500, 1 ≤ M ≤ 5000), indicating the items’ number and the initial money. Then N lines follow, each line contains three numbers Pi, Qi and Vi (1 ≤ Pi ≤ Qi ≤ 100, 1 ≤ Vi ≤ 1000), their meaning is in the description.

The input terminates by end of file marker.

Output
For each test case, output one integer, indicating maximum
value iSea could get.

Sample Input
2 10
10 15 10
5 10 5
3 10
5 10 5
3 5 6
2 7 3

Sample Output
5
11

题意:有n件商品,每件商品的价格是pi,每件商品只有在总钱数大于等于qi时才可以买入,每件商品都有评估价值vi。现在共有M元钱,如何实现使买到的商品价值最大。

分析题中的第二个例子:
3 10
5 10 5…A商品
3 5 6…B商品
2 7 3…C商品
输出的结果为11

对于这个例子,正确的购买方法是先买A后买B(考虑到题目的附加要求提到只有钱数大于等于qi时才能够买入),这样就可以得到最大价值11,不能先B后A。
所以,结果和购买的顺序有很大关系,但是如果qi=pi,那么结果跟顺序没有关系,那么此时就是典型的01背包问题了。(01背包状态转移方程:f[n, m]= max(f[n-1, m],f[n-1, m-pn]+vn))
接下来,考虑有q的情况,在这里引用一下其他博主的分析,讲的很易懂:

不妨把大顺序确定下来。也就是说,比方说A、B、C三样商品,我们不管他买不买,我们只要确定下来如果他买,那肯定先买A再买C,那接下来是不是就不需要考虑顺序,
只需要使用0/1背包算法直接来。这就是我们的思路,先把顺序给考虑了,在套用0/1背包算法。我们举第二个例子,我们稍微改一下,得到:
3 10
5 5 5 ----A商品
3 3 6 ----B商品
2 3 3 ----C商品
其实,就是让C商品的q不等于p,其他都相同,这时,你就会发现如果要买C商品的话,肯定得先买C商品,因为买C商品的代价最大。所以,我们可以按照qi-pi的顺序来确定大顺序。
这里我们还可以用更严谨的方式来证明一下,比如A:p1 q1, B:p2 q2,然后,假设单独买A或者B的话,都是可以买到的。这时,若先买A,则你至少需要p1+q2的钱;若先买B,则至少需要p2+q1的钱。
那肯定是花最少的钱咯,所以如果先买A再买B,那么p1+q2<p2+q1,转换一下,就是q1-p1>q2-p2,也就是说qi-pi大的先买。这里还得注意一点就是,排序的时候,得按照qi-pi从小到大排序,
因为你买第n件商品的时候,是在比较你是否要先买第n件商品。打个比方让大家更好地理解,比如说f(3, 10),是不是max(f(2, 10-p3)+v3, f(2, 10)),你会发现这个第一种情况f(2,10-p3)+v3中,
是先买了第三件商品,也就是说排在后面的商品会先买。好的,排好序之后,就把问题就转换为不需要考虑顺序的问题了,那就是0/1背包问题了。

接下来就是完整代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 500
#define M 5000
struct item
{
    int pi;//商品的价格
    int qi;//商品的最低入手价格
    int vi;//商品携带的价值
}items[N+5];
int dp[M+5];//核心数组(优化过的)
bool cmp(item item1,item item2)
{
    return (item1.qi-item1.pi)<(item2.qi-item2.pi);//按照qi-pi从小到大排序,原因见上方证明过程
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        for(int i=1;i<=n;i++)
            cin>>items[i].pi>>items[i].qi>>items[i].vi;
        sort(items+1,items+n+1,cmp);//排序操作
        memset(dp,0,sizeof(dp));
        //优化01背包的模板写法
        for(int i=1;i<=n;i++)
            for(int j=m;j>=items[i].qi;j--)
            dp[j]=max(dp[j],dp[j-items[i].pi]+items[i].vi);
        cout<<dp[m]<<endl;
    }
    return 0;
}

无后效性:某阶段的状态一旦确定,则此后过程的演变不再受此前各种状态及决策的影响。

即当前的状态是此前历史的一个完整总结,此前的历史只能通过当前的状态去影响过程未来的演变,“未来与过去无关”。

所以,如果一个问题被划分各个阶段之后,阶段I中的状态只能由阶段i-1中(或多个有限历史阶段)的状态通过状态转移方程得来,与其它状态没有关系,特别是与未发生的状态没有关系。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值