洛谷 P1833 樱花 二进制优化的多重背包
棵樱花树,不同的树有不同的最多欣赏次数(0 时为无数),看每棵树每次都会花一定的时间,不同的树有不同的美学值,问在给定的时间内,可以得到的最大美学值为多少?
思路:混合背包 / 二进制优化
在过程中判断是 01背包 / 多重背包 / 完全背包
- 01 背包:每种物品只有一件
- 完全背包:每种物品无数
- 多重背包:每种物品有各自的数量限制
01 背包
表示前 件物品满足背包容量可以达到的最大价值,则
相当于考虑当前第 物品放还是不放。
for i=1...N
for v=V...c[i]
f[v]=max(f[v],f[v-c[i]]+w[i]);
这个是对二维数组的优化,其中 v
是倒序处理,因为更新的时候需要的是上一次状态的值,即 ,注意此处写成正序时实际上是完全背包——每个物品有无数件。
当背包必须装满时,初始化 其余都为 ,表示没有任何物品在背包时只有容量为 的背包是合法的。
当背包不要求必须装满时,初始化 都为
完全背包
每件物品可以有无数件
for i=1...N
for v=c[i]...V
f[v]=max(f[v],f[v-c[i]]+w[i])
多重背包
物品有 n[i]
件
for i=1...N
k=1
while k<n[i]
for v=V...k*c[i] // 01 背包
f[v]=max(f[v],f[v-k*c[i]]+k*w[i])
n[i]-=k
k*=2 // 二进制拆分
for v=V...n[i]*c[i] // 01 背包
f[v]=max(f[v],f[v-n[i]*c[i]]+n[i]*w[i])
注意这里的二进制拆分,是将一个数 拆成 ,其中每个数非负。
回到题目,完全背包可以看成数量很大的物体:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define MAXN 10010
#define MAXM 1010
using namespace std;
int m1,m2,s1,s2,n,T,t[MAXN],c[MAXN],p[MAXN],f[MAXM];
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d:%d %d:%d%d",&m1,&s1,&m2,&s2,&n);
T=(m2-m1)*60+(s2-s1);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&t[i],&c[i],&p[i]);
for(int i=1;i<=n;i++){
if(!p[i])
for(int v=t[i];v<=T;v++)
f[v]=max(f[v],f[v-t[i]]+c[i]);
else{
int k=1;
while(k<p[i]){
for(int v=T;v>=k*t[i];v--)
f[v]=max(f[v],f[v-k*t[i]]+k*c[i]);
p[i]-=k;
k*=2;
}
for(int v=T;v>=p[i]*t[i];v--)
f[v]=max(f[v],f[v-p[i]*t[i]]+p[i]*c[i]);
}
}
printf("%d\n",f[T]);
return 0;
}