Gift Hunting(分组背包)
Gift Hunting
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1418 Accepted Submission(s): 471
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
Source
2009 Asia Wuhan Regional Contest Hosted by Wuhan University
题意:
GG有两张奖券,面额分别为V1、V2,准备给MM买礼物。当天是MM生日,所以MM还可以免费得到一份礼物。
礼物有价格和幸福值两个参数,并且礼物分为特殊礼物和普通礼物,特殊礼物是一定要全部到手的。
两张奖券不可以合并使用,、一种礼物也只能买一次。
问MM最大幸福值是多少,如果特殊礼物不能全部得到MM会不高兴,幸福值为-1。
思路:先处理特殊的物品,看是不是可以买完,然后再买普通的物品
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long LL;
typedef pair<int ,int >pr;
const int Max = 110000;
pr SG[350];//Special Gift
pr NG[350];//Normal Gift
int SN,NN;//Special num && Normal num
int Dp[600][60][2];//Dp[i][j][k]表示在V1花费为i,V2花费为j时,状态为k是的幸福值k=1表示免费k=0表示没有免费的
int V1,V2,n;
bool GSG()//处理Special Gift;
{
int total,pretotal;
for(int i=0; i<=V1; i++)//初始化
{
for(int j=0; j<=V2; j++)
{
for(int k=0; k<=1; k++)
{
Dp[i][j][k]=-1;
}
}
}
Dp[0][0][0]=0;
total=0;
for(int i=0; i<SN; i++)
{
pretotal = total;//pretotal记录处理第i个礼物时已经必须购买的物品的总价值
total+=SG[i].second;//购买完当前物品后的总价值
for(int s1=V1; s1>=0; s1--)
{
for(int s2=V2; s2>=0; s2--)
{
if(Dp[s1][s2][1]==pretotal)//为了防止东西漏买,所以只处理价值等于pretotal,因为只有这种情况之前的东西才能全买
{
if(s1+SG[i].first<=V1)//限制条件
{
Dp[s1+SG[i].first][s2][1]=total;
}
if(s2+SG[i].first<=V2)
{
Dp[s1][s2+SG[i].first][1]=total;
}
}
if(Dp[s1][s2][0]==pretotal)//同上
{
if(s1+SG[i].first<=V1)
{
Dp[s1+SG[i].first][s2][0]=total;
}
if(s2+SG[i].first<=V2)
{
Dp[s1][s2+SG[i].first][0]=total;
}
Dp[s1][s2][1]=total;//可以免费买;
}
}
}
}
bool flag=false;//判断是不是可以将特殊的物品买完
for(int i=0; i<=V1; i++)
{
for(int j=0; j<=V2; j++)
{
for(int k=0; k<=1; k++)
{
if(Dp[i][j][k]==total)//如果价值与总价值相等,说明已经买完所有必须买的物品,否则归为-1,使的买普通物品时是建立在买完特殊物品的基础上
{
flag=true;
}
else
{
Dp[i][j][k]=-1;
}
}
}
}
return flag;
}
int GNG()
{
for(int i=0; i<NN; i++)
{
for(int s1=V1; s1>=0; s1--)
{
for(int s2=V2; s2>=0; s2--)
{
for(int k=0; k<=1; k++)
{
if(Dp[s1][s2][k]!=-1)//判断是不是在买完特殊物品后再买的状态
{
if(s1+NG[i].first<=V1&&Dp[s1][s2][k]+NG[i].second>Dp[s1+NG[i].first][s2][k])
{
Dp[s1+NG[i].first][s2][k]=Dp[s1][s2][k]+NG[i].second;
}
if(s2+NG[i].first<=V2&&Dp[s1][s2][k]+NG[i].second>Dp[s1][s2+NG[i].first][k])
{
Dp[s1][s2+NG[i].first][k]=Dp[s1][s2][k]+NG[i].second;
}
}
}
if(Dp[s1][s2][0]!=-1&&Dp[s1][s2][1]<Dp[s1][s2][0]+NG[i].second)//免费的物品,选择最优
{
Dp[s1][s2][1]=Dp[s1][s2][0]+NG[i].second;
}
}
}
}
int ans=0;
for(int i=0; i<=V1; i++)
{
for(int j=0; j<=V2; j++)
{
for(int k=0; k<=1; k++)
{
ans=max(ans,Dp[i][j][k]);
}
}
}
return ans;//选择最大的幸福值
}
int main()
{
int w=1;
int h,s,p;
while(scanf("%d %d %d",&V1,&V2,&n))
{
if(V1==0&&V2==0&&n==0)
{
break;
}
SN=0;
NN=0;
for(int i=0; i<n; i++)
{
scanf("%d %d %d",&p,&h,&s);
if(s==1)
{
SG[SN].first=p;
SG[SN++].second=h;
}
else
{
NG[NN].first=p;
NG[NN++].second=h;
}
}
if(GSG())//如果可以将特殊物品买完
{
printf("Case %d: %d\n\n",w++,GNG());
}
else
{
printf("Case %d: -1\n\n",w++);
}
}
return 0;
}