洛谷P1833 樱花

题目描述

爱与愁大神后院里种了n棵樱花树,每棵都有美学值Ci。爱与愁大神在每天上学前都会来赏花。爱与愁大神可是生物学霸,他懂得如何欣赏樱花:一种樱花树看一遍过,一种樱花树最多看Ai遍,一种樱花树可以看无数遍。但是看每棵樱花树都有一定的时间Ti。爱与愁大神离去上学的时间只剩下一小会儿了。求解看哪几棵樱花树能使美学值最高且爱与愁大神能准时(或提早)去上学。

输入格式
共n+1行:
第1行:三个数:现在时间Ts(几点:几分),去上学的时间Te(几点:几分),爱与愁大神院子里有几棵樱花树n。
第2行~第n+1行:每行三个数:看完第i棵树的耗费时间Ti,第i棵树的美学值Ci,看第i棵树的次数Pi(Pi=0表示无数次,Pi是其他数字表示最多可看的次数Pi)。

输出格式
只有一个整数,表示最大美学值。 题目链接

很明显是一个多重背包
f[i][j] 表示从前i-1个物品中选,时间为j的最大方案数
f[i][j] = max(f[i][j], f[i-1][j-kv[i]] + kw[i]);

未优化版本TLE

#include <bits/stdc++.h>

using namespace std;

const int N = 10010;

int a,b,c,d,n;
int f[N][1010];
int t[N],w[N],s[N];

int main()
{
    scanf("%d:%d %d:%d%d",&a,&b,&c,&d,&n);
    int m = (c-a)*60 + d - b;
    
    for(int i = 1;i <= n;i++)
    {
        cin >> t[i] >> w[i] >> s[i];
        if(s[i] == 0) s[i] = 100000;
    }
    
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
            for(int k = 0;k*t[i] <= j && k <= s[i];k++)
                f[i][j] = max(f[i-1][j - k*t[i]] + k*w[i],f[i][j]);

    cout << f[n][m] << endl;
    return 0;
}

那么我们使用多重背包的二进制优化,把多重背包优化成01背包

#include <bits/stdc++.h>

using namespace std;

const int N = 10010;

int a,b,c,d,n;
int f[1010];
int t[N*10],w[N*10];

int main()
{
    scanf("%d:%d%d:%d%d",&a,&b,&c,&d,&n);
    int m = (c-a)*60 + d - b;
    
    int cnt = 0;
    for(int i = 1;i <= n;i++)
    {
        int k = 1;
        int a,b,s;
        cin >> a >> b >> s;
        
        if(s == 0) s = 100000;
        
        while(k <= s)
        {
            cnt++;
            t[cnt] = a*k;
            w[cnt] = b*k;
            s -= k;
            k *= 2;
        }
        
        if(s > 0)
        {
            cnt++;
            t[cnt] = a*s;
            w[cnt] = b*s;
        }
    }
    
    for(int i = 1;i <= cnt;i++)
        for(int j = m;j >= t[i];j--)
            f[j] = max(f[j], f[j-t[i]] + w[i]);
    
    cout << f[m] << endl;
    
    return 0;
}
原文地址:https://www.cnblogs.com/zcxy/p/12903695.html