【题目描述:】
爱与愁大神后院里种了n棵樱花树,每棵都有美学值Ci。爱与愁大神在每天上学前都会来赏花。爱与愁大神可是生物学霸,他懂得如何欣赏樱花:一种樱花树看一遍过,一种樱花树最多看Ai遍,一种樱花树可以看无数遍。但是看每棵樱花树都有一定的时间Ti。爱与愁大神离去上学的时间只剩下一小会儿了。求解看哪几棵樱花树能使美学值最高且爱与愁大神能准时(或提早)去上学。
【输入格式:】
共n+1行:
第1行:三个数:现在时间Ts(几点:几分),去上学的时间Te(几点:几分),爱与愁大神院子里有几棵樱花树n。
第2行~第n+1行:每行三个数:看完第i棵树的耗费时间Ti,第i棵树的美学值Ci,看第i棵树的次数Pi(Pi=0表示无数次,Pi是其他数字表示最多可看的次数Pi)。
【输出格式:】
只有一个整数,表示最大美学值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
输入样例#1: 6:50 7:00 3 2 1 0 3 3 1 4 5 4 输出样例#1: 11
【算法分析:】
01背包可以看做是只有一件物品的多重背包,所以可将三类背包问题化为两类:
- 多重背包
- 完全背包
但多重背包直接做时间复杂度太大,所以需要二进制优化,此时如何处理完全背包问题?
可以将完全背包的数量看做一个比较大,而数组中也存的开的数,比如9999,然后当做多重背包来做.
【代码:】
1 //P1833 樱花 2 #include<iostream> 3 #include<cstdio> 4 using namespace std; 5 6 const int MAXN = 1000000 + 1; 7 const int INF = 9999; 8 9 int n, T; 10 int t[MAXN], c[MAXN], p[MAXN]; 11 int a[MAXN], b[MAXN], f[MAXN]; 12 struct Time { 13 int h, min; 14 }s, e; 15 16 inline int read() { 17 int x=0, f=1; char ch=getchar(); 18 while(ch<'0' || ch>'9') { 19 if(ch == '-') f = -1; 20 ch = getchar(); 21 } 22 while(ch>='0' && ch<='9') 23 x=(x<<3) + (x<<1) + ch-48, ch = getchar(); 24 return x * f; 25 } 26 27 int main() { 28 s.h = read(), s.min = read(); 29 e.h = read(), e.min = read(); 30 n = read(); 31 T = e.min - s.min + (e.h - s.h) * 60; 32 int cnt = 0; 33 for(int i=1; i<=n; ++i) { 34 t[i] = read(), c[i] = read(), p[i] = read(); 35 if(!p[i]) p[i] = INF; 36 int s = 1; 37 while(p[i] > s) { 38 a[++cnt] = t[i] * s; 39 b[cnt] = c[i] * s; 40 p[i] -= s; 41 s <<= 1; 42 } 43 if(p[i]) { 44 a[++cnt] = t[i] * p[i]; 45 b[cnt] = c[i] * p[i]; 46 } 47 } 48 for(int i=1; i<=cnt; ++i) 49 for(int j=T; j>=a[i]; --j) 50 f[j] = max(f[j], f[j - a[i]] + b[i]); 51 printf("%d\n", f[T]); 52 }