题目
题目描述
【题目背景】
众所周知,机房里有三个人,一个是 THU 的,一个是 PKU 的,最弱的是 FDU 的。稀有就 是那个 FDU 的„稀有特别喜欢吃东西,但是又喜欢打游戏„结果就忙得不可开交„
【问题描述】
稀有打算去超市买点东西,他身上共有 N 元钱,其中 K 元钱都是准备用来买游戏打的, 因此十分蛋疼的就是剩下的钱安排买什么了。超市的每件东西有很多类,第一类只有价格和 给稀有带来的愉悦值,但是每种只有一件;第二类每种有无数件,同样有价格和愉悦值;其 他类除了每一种有价格和愉悦值之外,每一类一共只能取一件。(我会告诉你稀有去了 HZ 之后身上没钱了?)
输入
输入文件 shop.in 共有 M+1 行。
第一行包含三个整数,N,K,M,N,K 如题意,M 为东西个数。
第二至 M+1 行包含三个正整数,分别表示价格 Pi,愉悦值 Wi,属于哪一类 Ci。
输出
输出文件 shop.out 只有一行,最大愉悦值。
样例输入
100 70 2
31 1000 1
30 2 2
样例输出
2
样例解释:买第二件啊!只买得起第二件了啊!有木有!!坑爹啊,愉悦值只有 2 啊!!
数据范围限制
对于 50%的数据,只含前两类物品。
对于 100%的数据,K<=N<=20000,M<=1000,|Wi|<=10000,|Pi|<=10000。
最多一共有 1000 类物品,类型最大为第 1000 类。
题解
这题显然是3个背包嘛。第一类的01背包,第二类的无限背包。
这样可以拿50分。
至于第三个背包,我们知道同一类物品最多只能够选一个,所以我们要在每一类物品中选最优的那一个。
(其中a表示类数>2的物品,所有的a[k].c都是一样的(c表示类别))
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 20010
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note
{
int p,w,c;
};
note a1[N],a2[N],a3[N];
bool cmp(note x,note y)
{
return x.c<y.c;
}
int f[N],i,j,k,last,n,m,ans,x,y,z,_1,_2,_3;
int main()
{
freopen("shop.in","r",stdin);
freopen("shop.out","w",stdout);
scanf("%d%d%d",&n,&k,&m);
n-=k;
fo(i,1,m)
{
scanf("%d%d%d",&x,&y,&z);
if (z==1) a1[++_1].p=x,a1[_1].w=y,a1[_1].c=z;else
if (z==2) a2[++_2].p=x,a2[_2].w=y,a2[_2].c=z;else
a3[++_3].p=x,a3[_3].w=y,a3[_3].c=z;
}
fo(i,1,_1)
fd(j,n,a1[i].p)
f[j]=max(f[j],f[j-a1[i].p]+a1[i].w);
fo(i,1,_2)
fo(j,a2[i].p,n)
f[j]=max(f[j],f[j-a2[i].p]+a2[i].w);
sort(a3+1,a3+_3+1,cmp);
last=1;
fo(i,1,_3)
if (a3[i].c!=a3[i+1].c)
{
int mn=2147483647;
fo(k,last,i) mn=min(mn,a3[k].p);
fd(j,n,mn)
fo(k,last,i)
if (a3[k].p<=j)
f[j]=max(f[j],f[j-a3[k].p]+a3[k].w);
last=i+1;
}
fo(i,0,n) ans=max(ans,f[i]);
printf("%d",ans);
}