题目来源:洛谷
题目描述
爱与愁大神后院里种了n棵樱花树,每棵都有美学值Ci。爱与愁大神在每天上学前都会来赏花。爱与愁大神可是生物学霸,他懂得如何欣赏樱花:一种樱花树看一遍过,一种樱花树最多看Ai遍,一种樱花树可以看无数遍。但是看每棵樱花树都有一定的时间Ti。爱与愁大神离去上学的时间只剩下一小会儿了。求解看哪几棵樱花树能使美学值最高且爱与愁大神能准时(或提早)去上学。
输入格式
共n+1行:
第1行:三个数:现在时间Ts(几点:几分),去上学的时间Te(几点:几分),爱与愁大神院子里有几棵樱花树n。
第2行~第n+1行:每行三个数:看完第i棵树的耗费时间Ti,第i棵树的美学值Ci,看第i棵树的次数Pi(Pi=0表示无数次,Pi是其他数字表示最多可看的次数Pi)。
输出格式
只有一个整数,表示最大美学值。
输入输出样例
输入 #1
6:50 7:00 3
2 1 0
3 3 1
4 5 4
输出 #1
11
数据范围:
100%数据:Te-Ts ≤ 1000,n ≤ 10000
样例解释:
赏第一棵樱花树一次,赏第三棵樱花树2次
思路:
很裸的混合背包,每棵樱花树可以看的次数有无限次,有限次(1或其他),我们可以尝试将二者用二进制拆分转换成多重背包,然后跑01背包的模板,思路很容易明白,那如何转换?可以参考P1776 宝物筛选_NOI导刊2010提高(02)
另外还要注意的是时间的问题,这里的时间是24小时制,在读入的时候要计算出可以观赏的时间
code:
#include<bits/stdc++.h>
using namespace std;
int x1,yy,x2,y2,n,W,cnt,f[11000000];
struct node{
int w;
int v;
int num;
}a[11000000];
int main()
{
scanf("%d:%d %d:%d",&x1,&yy,&x2,&y2);
scanf("%d",&n);
if(yy>y2)
{
y2+=60;
x2--;
}
W=(x2-x1)*60+y2-yy;
for (int i=1;i<=n;i++)
{
int w,v,num;
scanf("%d%d%d",&w,&v,&num);
if (num==0) num=9999999;
for (int j=1;j<=num;j<<=1)
{
a[++cnt].w=j*w;
a[cnt].v=j*v;
num-=j;
if (a[cnt].w>W) {num=0;cnt--;break;}
}
if (num!=0) a[++cnt].w=num*w,a[cnt].v=num*v;
}
for (int i=1;i<=cnt;i++)
for (int j=W;j>=a[i].w;j--)
f[j]=max(f[j],f[j-a[i].w]+a[i].v);
printf("%d\n",f[W]);
return 0;
}