1. 程式人生 > >多重揹包之二進位制優化

多重揹包之二進位制優化

傳送門

分析

多重揹包,就是在0/1揹包的基礎上,固定每個物品選的上限(最多選多少個)

最簡單的方法就是直接拆分

將第i種物品看做獨立的ci個物品,轉化為0/1揹包即可

但這樣顯然不優,於是我們想到了二進位制

 把物品的件數C 用分解成若干個件數的集合,這裡面數字可以組合成任意小於等於C的件數,而且不會重複,之所以叫二進位制分解,是因為這樣分解可以用數字的二進位制形式來解釋比如:7的二進位制 7 = 111 它可以分解成 001 010 100 這三個數可以組合成任意小於等於7 的數,而且每種組合都會得到不同的數15 = 1111 可分解成 0001  0010  0100  1000 四個數字 如果13 = 1101 則分解為 0001 0010 0100 0110 前三個數字可以組合成 7以內任意一個數,加上 0110 = 6 可以組合成任意一個大於6 小於13的數,雖然有重複但總是能把 13 以內所有的數都考慮到了,基於這種  思想去把多件物品轉換為,多種一件物品,就可用01 揹包求解了。  

這道題顯然板題

程式碼

#include<bits/stdc++.h>
#define in read()
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return f==1?res:-res;
}
int n,w,f[500009];
int val[500009],weight[500009],cnt=0;
int main(){
	n=in;w=in;
	int i,j,v,z,shu;
	for(i=1;i<=n;++i){
		v=in;z=in;shu=in;
		for(j=1;j<=shu;j<<=1){//拆分
			val[++cnt]=v*j;
			weight[cnt]=z*j;
			shu-=j;
		}
		if(shu){
			val[++cnt]=shu*v;
			weight[cnt]=shu*z;
		}
	}
	for(i=1;i<=cnt;++i)
		for(j=w;j>=weight[i];--j)
			f[j]=max(f[j],f[j-weight[i]]+val[i]);
	int ans=-1;
	for(i=0;i<=w;++i)	ans=max(ans,f[i]);
	cout<<ans;
	return 0;
}