【Luogu P1833】混合背包——樱花

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;
}

二进制拆分的代码将在后续更新

posted @ 2020-04-21 20:54  Nanjo  阅读(147)  评论(0编辑  收藏  举报