【洛谷】【动态规划/背包】P1833 樱花

【题目描述:】

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

【输入格式:】

共n+1行:

第1行:三个数:现在时间Ts(几点:几分),去上学的时间Te(几点:几分),爱与愁大神院子里有几棵樱花树n。

第2行~第n+1行:每行三个数:看完第i棵树的耗费时间Ti,第i棵树的美学值Ci,看第i棵树的次数Pi(Pi=0表示无数次,Pi是其他数字表示最多可看的次数Pi)。

【输出格式:】

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

输入样例#16:50 7:00 3
2 1 0
3 3 1
4 5 4
输出样例#111
输入输出样例

【算法分析:】

01背包可以看做是只有一件物品的多重背包,所以可将三类背包问题化为两类:

  1. 多重背包
  2. 完全背包

但多重背包直接做时间复杂度太大,所以需要二进制优化,此时如何处理完全背包问题?

可以将完全背包的数量看做一个比较大,而数组中也存的开的数,比如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
", f[T]);
52 }
原文地址:https://www.cnblogs.com/devilk-sjj/p/9065567.html