题目背景
《爱与愁的故事第四弹·plant》第一章。
题目描述
爱与愁大神后院里种了n棵樱花树,每棵都有美学值Ci。爱与愁大神在每天上学前都会来赏花。爱与愁大神可是生物学霸,他懂得如何欣赏樱花:一
种樱花树看一遍过,一种樱花树最多看Ai遍,一种樱花树可以看无数遍。但是看每棵樱花树都有一定的时间Ti。爱与愁大神离去上学的时间只剩下一
小会儿了。求解看哪几棵樱花树能使美学值最高且爱与愁大神能准时(或提早)去上学。
输入格式:
共n+1行:
第1行:三个数:现在时间Ts(几点:几分),去上学的时间Te(几点:几分),爱与愁大神院子里有几棵樱花树n。
第2行~第n+1行:每行三个数:看完第i棵树的耗费时间Ti,第i棵树的美学值Ci,看第i棵树的次数Pi(Pi=0表示无数次,Pi是其他数字表示最多可看的次数Pi)。
输出格式:
只有一个整数,表示最大美学值。
输入样例:
6:50 7:00 3
2 1 0
3 3 1
4 5 4
输出样例:
11
说明
100%数据:Te-Ts ≤ 1000,n ≤ 1000
样例解释:赏第一棵樱花树一次,赏第三棵樱花树2次
题解:
这题可谓是01背包的综合题。
First,有个数,那么就是二进制拆分二进制拆分原理。Secend,单个的,就是倒着枚举。Third,无限,就是正向循环枚举。(详见代码)
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1005*50;
int n,nn,tim,a[maxn],w[maxn],f[maxn];
bool kid[maxn];//表示是否无限个
int read()
{
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int gettime(){return -read()*60-read()+read()*60+read();}
int main()
{
tim=gettime();nn=read();
for (int i=1;i<=nn;i++)
{
int T=read(),C=read(),P=read();
if (!P) {kid[++n]=1;a[n]=C;w[n]=T;continue;}
for (int j=1;;j<<=1)//二进制拆分
{
if (P>=j) P-=j;else break;
if (T*j>tim) break;//如果当前拆出的>总时间,那么就舍弃
a[++n]=C*j,w[n]=T*j;
}
if (P&&P<=tim) a[++n]=C*P,w[n]=T*P;//如果有剩余部分,且不大于总时间,那么也需要留下
}
for (int i=1;i<=n;i++)
{
if (kid[i]) for (int j=w[i];j<=tim;j++) f[j]=max(f[j],f[j-w[i]]+a[i]);else//无限次
for (int j=tim;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+a[i]);//有限次
}
printf("%d",f[tim]);
return 0;
}