HDU 3236 Gift Hunting(0-1背包变异)

本文介绍了一个特定条件下为女友挑选礼物的问题,通过使用两张不同价值的优惠券及一次免费获取机会,来最大化女友的幸福感。该问题可以转化为一种0-1背包问题的变种,并通过动态规划求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gift Hunting

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1743    Accepted Submission(s): 581


Problem Description
After winning two coupons for the largest shopping mart in your city, you can't wait inviting your girlfriend for gift hunting. Having inspected hundreds of kinds of souvenirs, toys and cosmetics, you finally narrowed down the candidate list to only n gifts, numbered 1 to n. Each gift has a happiness value that measures how happy your girlfriend would be, if you get this gift for her. Some of them are special - you must get it for your girlfriend (note that whether a gift is special has nothing to do with its happiness value).

Coupon 1 can be used to buy gifts with total price not greater than V1 (RMB). Like most other coupons, you can’t get any money back if the total price is strictly smaller than V1. Coupon 2 is almost the same, except that it’s worth V2. Coupons should be used separately. That means you cannot combine them into a super-coupon that’s worth V1+V2. You have to divide the gifts you choose into two part, one uses coupon 1, the other uses coupon 2.

It is your girlfriend's birthday today. According to the rules of the mart, she can take one (only one) gift for FREE! Here comes your challenge: how to make your girlfriend as happy as possible?
 

Input
There will be at most 20 test cases. Each case begins with 3 integers V1, V2 and n (1 <= V1 <= 500, 1 <= V2 <= 50, 1 <= n <= 300), the values of coupon 1 and coupon 2 respectively, and the number of candidate gifts. Each of the following n lines describes a gift with 3 integers: P, H and S, where P is the price, H is the happiness (1 <= P,H <= 1000), S=1 if and only if this is a special gift - you must buy it (or get it for free). Otherwise S=0. The last test case is followed by V1 = V2 = n = 0, which should not be processed.
 

Output
For each test case, print the case number and the maximal total happiness of your girlfriend. If you can't finish the task, i.e. you are not able to buy all special gifts even with the 1-FREE bonus, the happiness is -1 (negative happiness means she's unhappy). Print a blank line after the output of each test case.
 

Sample Input
3 2 4 3 10 1 2 10 0 5 100 0 5 80 0 3 2 4 3 10 1 2 10 0 5 100 0 5 80 1 0 0 0
 

Sample Output
Case 1: 120 Case 2: 100



题意:有两张优惠券分别为v1,v2,和一次免费特权,你女朋友生日,问你用以上条件去退换礼物,每个礼物有一定的幸福指数,且有些礼物你必须买,如果特殊礼物不能全买输出-1,否则输出你能为你女朋友买到的最大的幸福指数。


解题思路:

每个物品只有两种选择方案,买或者不买,所以一想到是0-1背包,但是这题不是纯背包,是背包的变异。我们可以这样想,用两张优惠券分别去购买(并行着),假设dp[0,1][v1][v2],0表示还没有用免费机会,1 表示用了免费的机会,那么dp[0][v1][v2] 表示花了v1,v2还没使用免费的机会获得的最大的幸福指数,dp[1][v1][v2]表示用了免费的机会获得的最大的幸福指数。最后只要判断dp[1][v1][v2]是否大于0即可。


详细见代码:

<span style="font-size:18px;"> #include<iostream>
 #include<cstdio>
 #include<cstring>
 #include<algorithm>
 #include<cmath>
 #define INF 0x3f3f3f3
 using namespace std;
 int dp[2][505][55];
 int p[310],h[310],s[310];
 int main()
 {
     int v1,v2,n,cas=0;
     while(~scanf("%d %d %d",&v1,&v2,&n) && v1+v2+n){
        for(int i=1;i<=n;i++){
            scanf("%d %d %d",&p[i],&h[i],&s[i]);
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            int w=p[i],v=h[i];
            for(int j=v1;j>=0;j--){
                for(int k=v2;k>=0;k--){
                    int ans=dp[0][j][k];
                    if(s[i]==0){
                        dp[1][j][k]=max(dp[1][j][k],ans+v);
                        if(j>=w){
                            dp[0][j][k]=max(dp[0][j][k],dp[0][j-w][k]+v);
                            dp[1][j][k]=max(dp[1][j][k],dp[1][j-w][k]+v);
                        }
                        if(k>=w){
                            dp[0][j][k]=max(dp[0][j][k],dp[0][j][k-w]+v);
                            dp[1][j][k]=max(dp[1][j][k],dp[1][j][k-w]+v);
                        }
                    }
                    else{
                        dp[1][j][k]=ans+v;
                        if(j>=w && k>=w){
                            dp[0][j][k]=max(dp[0][j][k-w],dp[0][j-w][k])+v;
                            dp[1][j][k]=max(dp[1][j][k-w],dp[1][j-w][k])+v;
                        }
                        else if(j>=w){
                            dp[0][j][k]=dp[0][j-w][k]+v;
                            dp[1][j][k]=max(dp[1][j-w][k]+v,dp[1][j][k]);
                        }
                        else if(k>=w){
                            dp[0][j][k]=dp[0][j][k-w]+v;
                            dp[1][j][k]=max(dp[1][j][k-w]+v,dp[1][j][k]);
                        }
                        else dp[0][j][k]=-INF;
                    }
                }
            }
        }
        printf("Case %d: %d\n\n",++cas,dp[1][v1][v2]<0 ? -1 : dp[1][v1][v2]);
     }
     return 0;
 }
</span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值