题目描述
爱与愁大神后院里种了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
输出
11
很明显就是混合背包问题,01背包和完全背包可以直接套模板,多重背包可以二进制拆分转化为01背包,刚开始拆分又拆错了,每个多重背包有最大次数,拆分的物品不仅是小于他的二进制数还得满足这些数的和必须等于他的次数,因为物品的不能超过他的最大次数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;范围一定得开大点
ll n,m,x,w[N],t[N],dp[N],idx;
bool st[N];
int main()
{
int v,b,c,d,e;
scanf("%d:%d %d:%d %d",&b,&c,&d,&e,&n);
v=d*60+e-b*60-c;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&b,&c,&d);
if(!d)
{
t[idx]=b;
w[idx]=c;
st[idx++]=1;//标记完全背包
}
else
{
int cnt=1;
while(d>=cnt)//拆分,01背包的次数是1也不会拆错
{
t[idx]=1ll*b*(cnt);
w[idx++]=1ll*c*(cnt);
d-=cnt;
cnt= cnt<<1;
}
if(d!=0)
{
t[idx]=1ll*b*(d);
w[idx++]=1ll*c*(d);
}
}
}
n=idx;
for(int i=0;i<n;i++)
{
if(st[i])
for(int j=t[i];j<=v;j++)
dp[j]=max(dp[j],dp[j-t[i]]+w[i]);
else
for(int j=v;j>=t[i];j--)
dp[j]=max(dp[j],dp[j-t[i]]+w[i]);
}
cout<<dp[v];
return 0;
}