多重背包专题

多重背包专题

解析

与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;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值