混合背包(01、多重、完全)
洛谷P1833 樱花
题意:有n种物品,每种拿一个都消耗
T
i
T_i
Ti。有的只能拿一个,有的最多拿
a
i
a_i
ai个,有的可以拿无数个(每种物品可拿
P
i
P_i
Pi次)。每种物品的价值是
c
i
c_i
ci,背包容量是
T
T
T,求能获得的最大价值。
思路:
这题就是01背包+多重背包+完全背包。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=10000;
int dp[1003];//前:第几种物品 后:所装多少
int t[maxn+2],c[maxn+2],p[maxn+2];
int m;//全局变量:总时间(背包容量)
void completepack(int i,int cost,int weight){
for(int j=0;j<=m;j++){
if(j>=cost)dp[j]=max(dp[j],dp[j-cost]+weight);
}
}
void zeroonepack(int i,int cost,int weight){ // 倒序枚举
for(int j=m;j>=0;j--){
if(j>=cost)
dp[j]=max(dp[j],dp[j-cost]+weight);
}
}
void multiplepack(int i,int cost,int weight,int amount){
if(cost*amount>=m){
completepack(i,cost,weight);
return;
}
int k=1;
while(k<amount){
zeroonepack(i,k*cost,k*weight);
amount-=k;
k*=2;
}
zeroonepack(i,amount*cost,amount*weight);
}
int main(){
int h1,m1,h2,m2,n;
scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&n);
for(int i=1;i<=n;i++)scanf("%d%d%d",&t[i],&c[i],&p[i]);
int mx=m2-m1;
int hx=(h2-h1)*60;
if(mx<0)hx=(h2-h1-1)*60;
if(mx<0)mx=60-m1+m2;
m=hx+mx;
for(int i=1;i<=n;i++){
if(p[i]==0)completepack(i,t[i],c[i]);
else multiplepack(i,t[i],c[i],p[i]);
}
printf("%d\n",dp[m]);
}
分组背包
bitset优化
牛客:简单瞎搞题
#include<bits/stdc++.h>
using namespace std;
const int maxn = 103;
int l[maxn],r[maxn];
bitset<maxn*maxn*maxn>dp[2];
// 01背包:一个物品放一次
// 多重背包:一个物品放a[i]次
// 完全背包:一个物品放无限次
// 当前:多个物品放一次
int main(){
int n;cin>>n;
for(int i=1;i<=n;++i) scanf("%d%d",&l[i],&r[i]);
int flg=0;
// bitset要处理第一对
for(int i=l[1];i<=r[1];++i) dp[flg].set(i*i);
for(int i=2;i<=n;++i){
flg^=1;
dp[flg].reset();
for(int k=l[i];k<=r[i];++k){
dp[flg] |= dp[flg^1]<<(k*k);
/*
其实等价于
for(int j=1;j<=(1e2)^3;++j){
if(j>=k*k && dp[flg][j-k*k]) dp[flg][j] = 1;
}
*/
}
}
cout<<dp[flg].count()<<endl;
}