码迷,mamicode.com
首页 > 其他好文 > 详细

背包九讲之二(完全背包)

时间:2015-02-07 15:44:25      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:

 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 */

 

/*有n种物品和一个容量为v的背包,每件物品可以无限使用,第i件物品的费用为c[i],价值为w[i],求解哪些物品装入背包费用不超过背包容量且价值总和最大基本思路是dp[i][j] = max{dp[i-1][j-k*c[i]] k*c[i]<=j}和01背包一样有V*N个状态,但是每个状态的求解不再是O(1)了,求解状态dp[i][j]是O(j/c[i]),总的时间复杂度超过O(V*N)
可以转化为01背包问题从而求解(1)第i件物品可以转化为v/c[i]件物品,从而转化为01背包问题(2)一种更加好的方法是将第二种物品转化为费用c[i]*2^k,价值w[i]*2^k的若干件物品,其中k满足c[i]*2^k<=v.这是二进制的思想。因为不管最优策选择几件第i中物品,都可以用若干个2^k件物品来表示,这样就把每种物品拆分为log(v/c[i])种物品
但是有更优的O(VN)算法for(i=1; i<=n; ++i)for(j=v[i]; j<=v; ++j)dp[j] = max(dp[j],dp[j-c[i]+w[i]);
其实可以这么想  dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+w[i]);dp[i][j]可以转化为上一层的dp[i-1][j],也可以转化为这一层左边的状态所以要求比j小的状态要算出来,所以要求j从0-->v就是for(i=1; i<=n; ++i)for(j=0; j<=v; ++j){dp[i][j] = dp[i-1][j];if(j>=v[i])dp[i][j] = max(dp[i][j],dp[i][j-c[i]]+w[i]);}转化为一维的状态就是for(i=1; i<=n; ++i)for(j=v[i]; j<=v; ++j)dp[j] = max(dp[j],dp[j-c[i]]+w[i]);*/#include <stdio.h>#include <string.h>int dp[111][1111];int dp2[1111];int c[111],w[111];inline int max(const int &a, const int &b){return a < b ? b : a;}int main(){int n,v,i,j,k;while(scanf("%d%d",&n,&v)!=EOF){for(i=1; i<=n; ++i)scanf("%d",&w[i]);for(i=1; i<=n; ++i)scanf("%d",&c[i]);memset(dp,0,sizeof(dp));memset(dp2,0,sizeof(dp2));for(i=1; i<=n; ++i){for(j=0; j<=v; ++j){dp[i][j] = dp[i-1][j];if(j>=c[i]){dp[i][j] = max(dp[i][j],dp[i][j-c[i]]+w[i]);dp2[j] = max(dp2[j],dp2[j-c[i]]+w[i]);}}}printf("%d\n",dp[n][v]);printf("%d\n",dp2[v]);}return 0;}
/*sample input:5 101 2 5 4 62 2 6 5 4
sample output:
*/

背包九讲之二(完全背包)

标签:

原文地址:http://www.cnblogs.com/justPassBy/p/4278759.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!