多重揹包問題描述:
有種物品,第種物品的體積是,價值是,每種物品的數量都是有限的,爲。現有容量爲的揹包,求在總體積不超過的條件下,使得揹包的總價值最大。
樸素算法:
將第類物品的個物品拆分,得個物品,即將原問題轉換爲了01揹包問題,時間複雜度爲。
也可以在轉移的過程中枚舉,表示第種物品選取的數量。
時間複雜度爲。
優化(二進制拆分):
二進制拆分:
一個數可以拆分爲個數字,分別爲
滿足使得這個數可以組合成任意小於等於的數。
由,移項,兩邊同時取數,得,即拆分得的數字個數。
7的二進制 7 = 111 分解所得的 這三個數可以組合成任意小於等於7 的數,每種組合都會得到不同的數。15 = 1111 可分解成四個數字,這四個數字進行組合也可以得到1-15之間的任一個數值。
優化:
將第種物品的個物品進行二進制拆分,得到得到拆分後的個物品,分別爲。
當爲13時,,故拆分成,根據二進制的性質,都可以由這四個數字組合得到。
例題:平分娃娃
#include<bits/stdc++.h>
using namespace std;
int m[7];
int w[14*6+1];
int dp[420001];
int main()
{
int V=0;
int t=1;
int j;
memset(dp,0,sizeof(dp));
for(int i=1;i<=6;i++){
cin>>m[i];
V+=m[i]*i;
int k=log2(m[i]+1);
for(j=0;j<=k-1;j++){
w[t++]=i*pow(2,j);
}
w[t++]=i*(m[i]-pow(2,k)+1);
}
if(V%2==0){
for(int i=1;i<=t-1;i++){
for(int j=V;j>=w[i];j--){
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
}
}
if(dp[V/2]==V/2){
cout<<"Can be divided.\n";
}
else{
cout<<"Can't be divided.\n";
}
}
else{
cout<<"Can't be divided.\n";
}
return 0;
}