【Luogu P1833】混合背包——樱花
根据题意,可以发现这是一个背包模型。但是它和01背包、完全背包不同之处在于有些树的选取有次数限制,有的却没有。
一个很容易想到的思路就是直接暴力地把所有\(p_i\)次限制的树视为01背包,外加一维选取个数的循环。剩下无限制的物品直接用完全背包来做。
这个思路很好实现,看上去也是非常完美。但是由于数据的构造,事实上会超时。
正解是二进制拆分,可是没学过啊,怎么办?
考虑一个玄学优化,如果说某棵树被选了\(p_i\)次后已经超过时间限制,那么事实上是无论如何也不会选完的。所以说此时我们可以将其视为完全背包,也就是说可以减少一维循环。
那么时间复杂度就得到了优化……至于优化了多少就要看数据给不给面子了……
当然运气很好的是这题可以过
#include<cstdio>
#include<algorithm>
using namespace std;
int ts,te,n,dp[1005],t[10005],c[10005],p[10005];
int main()
{
int s1,s2,t1,t2;
scanf("%d:%d %d:%d %d",&s1,&s2,&t1,&t2,&n);
ts=s1*60+s2;te=t1*60+t2;
int limit=te-ts;
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&t[i],&c[i],&p[i]);
if (p[i]*t[i]>limit) p[i]=0;
}
for (int i=1;i<=n;i++)
{
if (p[i]==0)
{
for (int j=t[i];j<=limit;j++)
dp[j]=max(dp[j],dp[j-t[i]]+c[i]);
}
else
{
for (int j=1;j<=p[i];j++)
for (int k=limit;k>=t[i];k--)
dp[k]=max(dp[k],dp[k-t[i]]+c[i]);
}
}
printf("%d",dp[limit]);
return 0;
}
二进制拆分的代码将在后续更新