多重背包专题
解析
与01背包,完全背包类似,只不过物品数量变为
k
k
k
这里有两种解决方法
1,直接拆分法,适用于数据较小的题目,实现容易
2,二进制拆分法,适用于数据较大的题目,实现较为复杂
T1 HDU2191
题解
完全背包板子,直接拆分法
代码
#include<bits/stdc++.h>
#define M 100009
using namespace std;
int read(){
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int a[M],b[M],c[M],f[M],n,m,t;
int main(){
t=read();
while(t--){
m=read(),n=read();
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++) a[i]=read(),b[i]=read(),c[i]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=c[i];j++)
for(int k=m;k>=a[i];k--)
f[k]=max(f[k],f[k-a[i]]+b[i]);
printf("%d\n",f[m]);
}return 0;
}
T2 HDU1171
题解
计算出总价值,对总价值的一半进行多重背包
代码
#include<bits/stdc++.h>
#define M 1000009
using namespace std;
int read(){
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int f[M],a[M],b[M],sum,n;
bool check(int mid){
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
for(int j=1;j<=b[i];j++)
for(int k=mid;k>=a[i];k--)
f[k]=max(f[k],f[k-a[i]]+a[i]);
return f[mid]!=mid;
}
int main(){
while(scanf("%d",&n)&&n>=0){
sum=0;memset(f,0,sizeof(f));
for(int i=1;i<=n;i++) a[i]=read(),b[i]=read(),sum+=a[i]*b[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=b[i];j++)
for(int k=sum>>1;k>=a[i];k--)
f[k]=max(f[k],f[k-a[i]]+a[i]);
printf("%d %d\n",max(f[sum>>1],sum-f[sum>>1]),min(f[sum>>1],sum-f[sum>>1]));
}return 0;
}
T3 HDU2844
题解
多重背包,二进制拆分法
代码
#include<bits/stdc++.h>
#define M 100009
using namespace std;
int read(){
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1;ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int f[M],val[M],num[M],ans,n,m;
int main(){
while(scanf("%d%d",&n,&m)){
if(!n&&!m) break;
memset(f,-0x3f,sizeof(f)),f[0]=0;
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1;i<=n;i++) num[i]=read();
for(int i=1;i<=n;i++){
int k=1,sum=num[i];
while(k<sum){
for(int j=m;j>=k*val[i];j--)
f[j]=max(f[j],f[j-k*val[i]]+k);
sum-=k;k<<=1;
}
for(int j=m;j>=sum*val[i];j--)
f[j]=max(f[j],f[j-sum*val[i]]+sum);
}for(int i=1;i<=m;i++) if(f[i]>0) ans++;
printf("%d\n",ans);ans=0;
}return 0;
}
T4 P1776
题解
多重背包,二进制拆分法
代码
#include<bits/stdc++.h>
#define M 100009
using namespace std;
int read(){
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1;ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int f[M],val[M],num[M],w[M],ans,n,m;
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) val[i]=read(),w[i]=read(),num[i]=read();
for(int i=1;i<=n;i++){
int k=1,sum=num[i];
while(k<sum){
for(int j=m;j>=k*w[i];j--)
f[j]=max(f[j],f[j-k*w[i]]+k*val[i]);
sum-=k;k<<=1;
}
for(int j=m;j>=sum*w[i];j--)
f[j]=max(f[j],f[j-sum*w[i]]+sum*val[i]);
}printf("%d\n",f[m]);
return 0;
}