【C++】洛谷P1833 樱花

本文介绍了一种通过算法解决赏樱美学值最大化的问题。故事背景是爱与愁大神需要在有限时间内观赏樱花树,每棵树都有不同的美学值、观赏时间和可观赏次数限制。文章详细解析了多重背包问题的解决方案,并提供了具体的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

樱花

题目背景

《爱与愁的故事第四弹·plant》第一章。

题目描述

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

输入格式

n+1n+1n+1行:

111 行:现在时间 TsT_sTs(几时:几分),去上学的时间 TeT_eTe(几时:几分),爱与愁大神院子里有几棵樱花树 nnn。这里的 TsT_sTsTeT_eTe 格式为:hh:mm,其中 0≤hh≤230 \leq hh \leq 230hh230≤mm≤590 \leq mm \leq 590mm59,且 hh,mm,nhh,mm,nhh,mm,n 均为正整数。

222 行到第 n+1n+1n+1 行,每行三个正整数:看完第 iii 棵树的耗费时间 TiT_iTi,第 iii 棵树的美学值 CiC_iCi,看第 iii 棵树的次数 PiP_iPiPi=0P_i=0Pi=0 表示无数次,PiP_iPi 是其他数字表示最多可看的次数 PiP_iPi)。

输出格式

只有一个整数,表示最大美学值。

样例 #1

样例输入 #1

6:50 7:00 3
2 1 0
3 3 1
4 5 4

样例输出 #1

11

提示

100%100\%100% 数据:Te−Ts≤1000T_e-T_s \leq 1000TeTs1000(即开始时间距离结束时间不超过 100010001000 分钟),n≤10000n \leq 10000n10000。保证 Te,TsT_e,T_sTe,Ts 为同一天内的时间。

样例解释:赏第一棵樱花树一次,赏第三棵樱花树 222 次。

思路: 多重背包问题,把物品经过二进制拆分之后再直接套01背包的代码即可。需要注意,当次数为无限时,此时是完全背包问题,需要单独判断一下并套用完全背包的状态转移方程

代码:

#include <bits/stdc++.h>
using namespace std;
int sth, stm, edh, edm, n, gap, t[1000005], c[1000005], p[1000005], a[10005], b[10005], d[10005], indexx = 1, dp[2][10005];
char tmp;
int main(){
    cin >> sth >> tmp >> stm >> edh >> tmp >> edm >> n;
    gap = (edh * 60 + edm) - (sth * 60 + stm);
    for(int i = 1; i <= n; i++){
        cin >> a[i] >> b[i] >> d[i];
    }
    for(int i = 1; i <= n; i++){
        if(d[i] != 0){
            int sum = 0, flag = 1;
            while(true){
                sum += flag;
                if(sum >= d[i]){
                    sum -= flag;
                    flag = d[i] - sum;
                    t[indexx] = a[i] * flag, c[indexx] = b[i] * flag, p[indexx] = flag;
                    indexx++;
                    break;
                }
                t[indexx] = a[i] * flag, c[indexx] = b[i] * flag, p[indexx] = flag;
                flag *= 2;
                indexx++;
            }
        }
        else t[indexx] = a[i], c[indexx] = b[i], p[indexx] = 0, indexx++;
    }
    for(int i = 1; i < indexx; i++){
        int now = i % 2, pre = (i + 1) % 2;
        for(int j = 0; j <= gap; j++){
            if(p[i] != 0){
                if(j >= t[i]) dp[now][j] = max(dp[pre][j], dp[pre][j - t[i]] + c[i]);
                else dp[now][j] = dp[pre][j];
            }
            else{
                if(j >= t[i]) dp[now][j] = max(dp[pre][j], dp[now][j - t[i]] + c[i]);
                else dp[now][j] = dp[pre][j];
            }
        }
    }
    cout << dp[(indexx - 1) % 2][gap];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值