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\n",dp[n][v]);
71 printf("%d\n",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 */