有 N N N种物品,第 i i i种物品的体积是 c i c_i ci,价值是 w i w_i wi,每种物品的数量都是有限的,为 n i n_i ni。现有容量为 V V V的背包,求在总体积不超过 V V V的条件下,使得背包的总价值最大。
将第 i i i类物品的 n i n_i ni个物品拆分,得 Σ n i \Sigma{n_i} Σni个物品,即将原问题转换为了01背包问题,时间复杂度为 O ( V × Σ n ) O(V\times\Sigma{n}) O(V×Σn)。
也可以在转移的过程中枚举 k k k,表示第 i i i种物品选取的数量。 d p [ i ] [ v ] = m a x ( d p [ i − 1 ] [ v − k ∗ c i ] + k ∗ w i ) , 0 ≤ k ≤ n i dp[i][v]=max(dp[i-1][v-k*c_i]+k*w_i),0\leq{k}\leq{n_i} dp[i][v]=max(dp[i−1][v−k∗ci]+k∗wi),0≤k≤ni
时间复杂度为 O ( V × Σ n ) O(V\times\Sigma{n}) O(V×Σn)。
一个数 n n n可以拆分为 x x x个数字,分别为
2 0 , 2 1 , 2 2 , . . . , 2 k − 1 , n − 2 k + 1 , 其中 k 是满足 n − 2 k + 1 > 0 的 最 大 整 数 。 2^0,2^1,2^2,...,2^{k-1},n-2^{k}+1,\text{其中}k\text{是满足}n-2^k+1>0的最大整数。 20,21,22,...,2k−1,n−2k+1,其中k是满足n−2k+1>0的最大整数。
满足使得这 x x x个数可以组合成任意小于等于 n n n的数。
由 n − 2 k + 1 > 0 n-2^k+1>0 n−2k+1>0,移项,两边同时取数,得 k < l o g ( n + 1 ) k
e . g . e.g. e.g. 7的二进制 7 = 111 分解所得的 001 , 010 , 100 001,010,100 001,010,100这三个数可以组合成任意小于等于7 的数,每种组合都会得到不同的数。15 = 1111 可分解成 0001 , 0010 , 0100 , 1000 0001,0010,0100,1000 0001,0010,0100,1000四个数字,这四个数字进行组合也可以得到1-15之间的任一个数值。
将第 i i i种物品的 n i n_i ni个物品进行二进制拆分,得到得到拆分后的 x x x个物品,分别为 ( c i , w i ) , ( 2 × c i , 2 × w i ) , ( 4 × c i , 4 × w i ) , . . . , ( 2 x − 1 × c i , 2 x − 1 × w i ) , ( ( n − 2 x + 1 ) × c i , ( n − 2 x + 1 ) × w i ) (c_i,w_i),(2\times c_i,2\times w_i),(4\times c_i,4\times w_i),...,(2^{x-1}\times c_i,2^{x-1}\times w_i),((n-2^x+1)\times c_i,(n-2^x+1)\times w_i) (ci,wi),(2×ci,2×wi),(4×ci,4×wi),...,(2x−1×ci,2x−1×wi),((n−2x+1)×ci,(n−2x+1)×wi)。
e . g . e.g. e.g.当 n n n为13时, x = ⌊ l o g ( 13 + 1 ) ⌋ = 3 x=\lfloor{log(13+1)}\rfloor=3 x=⌊log(13+1)⌋=3,故拆分成 1 , 2 , 4 , 6 1,2,4,6 1,2,4,6,根据二进制的性质, 1 ∼ 13 1\sim13 1∼13都可以由 1 , 2 , 4 , 6 1,2,4,6 1,2,4,6这四个数字组合得到。
#include
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;
}