前言
之前在 CSDN 上看某大佬讲解自己学DP刷了六十几题后完全领悟的故事,深有感触,自己实操了一下,刷了十几题以后就大概知道怎么转移了,这是洛谷比较火的一个动态规划题单链接,这里分享给大家。
题目描述
爱与愁大神后院里种了
n
n
n 棵樱花树,每棵都有美学值
C
i
(
0
≤
C
i
≤
200
)
C_i(0 \le C_i \le 200)
Ci(0≤Ci≤200)。爱与愁大神在每天上学前都会来赏花。爱与愁大神可是生物学霸,他懂得如何欣赏樱花:一种樱花树看一遍过,一种樱花树最多看
P
i
(
0
≤
P
i
≤
100
)
P_i(0 \le P_i \le 100)
Pi(0≤Pi≤100) 遍,一种樱花树可以看无数遍。但是看每棵樱花树都有一定的时间
T
i
(
0
≤
T
i
≤
100
)
T_i(0 \le T_i \le 100)
Ti(0≤Ti≤100)。爱与愁大神离去上学的时间只剩下一小会儿了。求解看哪几棵樱花树能使美学值最高且爱与愁大神能准时(或提早)去上学。
【数据范围】
100
%
100\%
100% 数据:
T
e
−
T
s
≤
1000
T_e-T_s \leq 1000
Te−Ts≤1000(即开始时间距离结束时间不超过
1000
1000
1000 分钟),
n
≤
10000
n \leq 10000
n≤10000。保证
T
e
,
T
s
T_e,T_s
Te,Ts 为同一天内的时间。
思路
原本思路:
首先对于每一个能看采无限次转化为能看
⌊
T
e
−
T
s
T
i
⌋
\lfloor \dfrac{T_e-T_s}{T_i} \rfloor
⌊TiTe−Ts⌋,否则较为难以处理。对于每一个能看
P
i
P_i
Pi 次的花转化为
p
i
p_i
pi 个能看
1
1
1 次的花,最后用 01
背包求解。时间复杂度
O ( T ∑ i = 1 c n t p i ) O(T\sum_{i=1}^{cnt}{p_i}) O(Ti=1∑cntpi)
考虑优化:
对于每一个能看 P i P_i Pi 次的花,我们一定要转化成 p i p_i pi 个吗?
考虑 p i p_i pi 的二进制形式,可以发现可以转化成 1 + 2 + 4 + 8 + ⋯ + 2 p o w + P i − ∑ j = 0 c n t 2 j 1+2+4+8+\dots+2^{pow}+P_i - \sum_{j=0}^{cnt}{2^j} 1+2+4+8+⋯+2pow+Pi−∑j=0cnt2j 的形式,即复杂度变为
O ( T ∑ i = 1 c n t log 2 p i ) O(T\sum_{i=1}^{cnt}{\log_2 p_i}) O(Ti=1∑cntlog2pi)
代码
#include<bits/stdc++.h>
#define time time_1
using namespace std;
int read(string x) {
int h = 0,min = 0,siz = x.size();
int i = 0;
for(;x[i] != ':';i++) h*=10,h+=int(x[i] - '0');
i++;
for(;i < siz;i++) min *= 10,min += int(x[i] - '0');
return h * 60 + min;
}
int n,t[100005],c[100005],cnt = 0;
int dp[2][100005];
string start,to;
int time;
signed main() {
cin>>start>>to;
cin>>n;
time = read(to) - read(start);
for(int i = 1;i <= n;i++) {
int t_1,c_1,b;
cin>>t_1>>c_1>>b;
if(b == 0) b = time / t_1;
int po = 1;
while(b >= po) {
t[++cnt] = po * t_1;
c[cnt] = po * c_1;
b -= po;
po *= 2;
//printf("%lld %lld\n",b,po);
}
if(b) {
t[++cnt] = b * t_1;
c[cnt] = b * c_1;
}
}
for(int i = 1;i <= cnt;i++) {
for(int j = 1;j <= time;j++) {
dp[i & 1][j] = dp[(i - 1) & 1][j];
if(j >= t[i]) dp[i & 1][j] = max(dp[i&1][j],dp[(i - 1)&1][j - t[i]] + c[i]);
}
}
printf("%lld\n",dp[cnt&1][time]);
return 0;
}