1 /* 2 有n种物品和一个容量为v的背包,每件物品可以无限使用, 3 第i件物品的费用为c[i],价值为w[i],求解哪些物品装入背包 4 费用不超过背包容量且价值总和最大 5 基本思路是dp[i][j] = max{dp[i-1][j-k*c[i]] k*c[i]<=j} 6 和01背包一样有V*N个状态,但是每个状态的求解不再是O(1)了, 7 求解状态dp[i][j]是O(j/c[i]),总的时间复杂度超过O(V*N) 8 9 可以转化为01背包问题从而求解 10 (1)第i件物品可以转化为v/c[i]件物品,从而转化为01背包问题 11 (2)一种更加好的方法是将第二种物品转化为费用c[i]*2^k,价值w[i]*2^k 12 的若干件物品,其中k满足c[i]*2^k<=v.这是二进制的思想。因为不管最优策选择 13 几件第i中物品,都可以用若干个2^k件物品来表示,这样就把每种物品拆分为 14 log(v/c[i])种物品 15 16 但是有更优的O(VN)算法 17 for(i=1; i<=n; ++i) 18 for(j=v[i]; j<=v; ++j) 19 dp[j] = max(dp[j],dp[j-c[i]+w[i]); 20 21 其实可以这么想 dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+w[i]); 22 dp[i][j]可以转化为上一层的dp[i-1][j],也可以转化为这一层左边的状态 23 所以要求比j小的状态要算出来,所以要求j从0-->v 24 就是 25 for(i=1; i<=n; ++i) 26 for(j=0; j<=v; ++j) 27 { 28 dp[i][j] = dp[i-1][j]; 29 if(j>=v[i]) 30 dp[i][j] = max(dp[i][j],dp[i][j-c[i]]+w[i]); 31 } 32 转化为一维的状态就是 33 for(i=1; i<=n; ++i) 34 for(j=v[i]; j<=v; ++j) 35 dp[j] = max(dp[j],dp[j-c[i]]+w[i]); 36 */ 37 #include <stdio.h> 38 #include <string.h> 39 int dp[111][1111]; 40 int dp2[1111]; 41 int c[111],w[111]; 42 inline int max(const int &a, const int &b) 43 { 44 return a < b ? b : a; 45 } 46 int main() 47 { 48 int n,v,i,j,k; 49 while(scanf("%d%d",&n,&v)!=EOF) 50 { 51 for(i=1; i<=n; ++i) 52 scanf("%d",&w[i]); 53 for(i=1; i<=n; ++i) 54 scanf("%d",&c[i]); 55 memset(dp,0,sizeof(dp)); 56 memset(dp2,0,sizeof(dp2)); 57 for(i=1; i<=n; ++i) 58 { 59 for(j=0; j<=v; ++j) 60 { 61 dp[i][j] = dp[i-1][j]; 62 if(j>=c[i]) 63 { 64 dp[i][j] = max(dp[i][j],dp[i][j-c[i]]+w[i]); 65 dp2[j] = max(dp2[j],dp2[j-c[i]]+w[i]); 66 } 67 } 68 } 69 70 printf("%d ",dp[n][v]); 71 printf("%d ",dp2[v]); 72 } 73 return 0; 74 } 75 76 /* 77 sample input: 78 5 10 79 1 2 5 4 6 80 2 2 6 5 4 81 82 sample output: 83 84 */