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

背包问题详解

时间:2015-07-31 23:06:17      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:

01背包

  一个背包中容量为V,现在有N个物品,每个物品的第i个 物品体积为weight[i],价值为value[i],现在往背包里面装东西,怎么装能使背包的内物品价值最大?这是01背包的最基础最根本的问题。01代表的意思是该物品取或者不取。顺便提一下各种背包之间的区别,完全背包每种物品的数目是无限种,多重背包的每种物品数目是有限中。

  用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是: 

        f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

  把这个过程理解为当取第i件物品是,价值为f[i-1][v-c[i]]+w[i];

  当不取第i件物品时,价值为f[i-1][v];

     作图便是如下:内层循环为v从1到V,外层循环是n从1到N;

              技术分享

  测试代码:

 1 #include<iostream>
 2 using namespace std;
 3 #define  V 1500
 4 unsigned int f[10][V];//全局变量,自动初始化为0
 5 unsigned int weight[10];
 6 unsigned int value[10];
 7 #define  max(x,y)    (x)>(y)?(x):(y)
 8 int main()
 9 {
10     
11     int N,M;
12     cin>>N;//物品个数
13     cin>>M;//背包容量
14     for (int i=1;i<=N; i++)
15     {
16         cin>>weight[i]>>value[i];
17     }
18     for (int i=1; i<=N; i++)
19         for (int j=1; j<=M; j++)
20         {
21             if (weight[i]<=j)
22             {
23                 f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]);
24             }
25             else
26                 f[i][j]=f[i-1][j];
27         }
28     
29     cout<<f[N][M]<<endl;//输出最优解
30 
31 }

 多重背包

  已知一个容量为v的背包和N件物品,第i件物品最多有num[i]件,没见物品的重量是weight[i],收益是cost[i];

  物品个数N = 3,背包容量为V = 8,则背包可以装下的最大价值为64.

                          技术分享

  基本思路:直接扩展01背包

  状态转移方程:

        f[i][j]=max{f[i-1][j],f[i-1][j-k*weight[i]+k*cost[i]};其中0<=k&&k<=j/weight[i],这是与01背包不同之处,边界条件。

  直接抄了网上的代码,如下:

 1 #include <iostream>
 2 using namespace std;
 3 const int N = 3;//物品个数
 4 const int V = 8;//背包容量
 5 int Weight[N + 1] = {0,1,2,2};
 6 int Value[N + 1] = {0,6,10,20};
 7 int Num[N + 1] = {0,10,5,2};
 8 int f[N + 1][V + 1] = {0};
 9 /*
10 f[i][v]:表示把前i件物品放入容量为v的背包中获得的最大收益。
11 f[i][v] = max(f[i - 1][v],f[i - 1][v - k * Weight[i]] + K * Value[i]);其中1 <= k <= min(Num[i],V/Weight[i])
12 //初始化
13 f[i][0] = 0;
14 f[0][v] = 0;
15 */
16 int MultiKnapsack()
17 {
18     int nCount = 0;
19     //初始化
20     for (int i = 0;i <= N;i++)
21     {
22         f[i][0] = 0;
23     }
24     for (int v = 0;v <= V;v++)
25     {
26         f[0][v] = 0;
27     }
28     //递推
29     for (int i = 1;i <= N;i++)
30     {
31         for (int v = Weight[i];v <= V;v++)
32         {
33             f[i][v] = 0;
34             nCount = min(Num[i],v/Weight[i]);//是当前背包容量v,而不是背包的总容量
35             for (int k = 0;k <= nCount;k++)
36             {
37                 f[i][v] = max(f[i][v],f[i - 1][v - k * Weight[i]] + k * Value[i]);
38             }
39         }
40     }
41     return f[N][V];
42 }
43 int main()
44 {
45     cout<<MultiKnapsack()<<endl;
46     system("pause");
47     return 1;
48 }

 完全背包

  完全背包只是每种物品的数量被放到了无限大,此时相对与多重背包变化的只是范围。

    有一个容量为V的背包和N件物品,第i件物品的重量是weight[i],收益是cost[i]。每种物品都有无限件,能放多少就放多少。在不超过背包容量的情况下,最多能获得多少价值或收益?

   1.基本思路:直接扩展01背包

  状态转移方程:

        f[i][v] = max(f[i - 1][v],f[i][v - K * weight[i]] + K * Value[i]); 其中 0<= K * weight[i] <= j,(v指此时背包容量,不是总容量)

 1 #include <iostream>
 2 #include <assert.h>
 3 using namespace std;
 4 /*
 5 f[i][v]:前i件物品放入背包容量为v的背包获得的最大收益
 6 
 7 f[i][v] = max(f[i - 1][v],f[i - 1][v - k * Wi] + k * Vi,其中 1<=k<= v/Wi)
 8 
 9 边界条件
10 f[0][v] = 0;
11 f[i][0] = 0;
12 */
13 
14 const int N = 3;
15 const int V = 5;
16 int weight[N + 1] = {0,3,2,2};
17 int Value[N + 1] = {0,5,10,20};
18 
19 int f[N + 1][V + 1] = {0};
20 
21 int Completeknapsack()
22 {
23     //边界条件
24     for (int i = 0;i <= N;i++)
25     {
26         f[i][0] = 0;
27     }
28     for (int v = 0;v <= V;v++)
29     {
30         f[0][v] = 0;
31     }
32     //递推
33     for (int i = 1;i <= N;i++)
34     {
35         for (int v = 1;v <= V;v++)
36         {
37             f[i][v] = 0;
38             int nCount = v / weight[i];
39             for (int k = 0;k <= nCount;k++)
40             {
41                 f[i][v] = max(f[i][v],f[i - 1][v - k * weight[i]] + k * Value[i]);
42             }
43         }
44     }
45     return f[N][V];
46 }
47 
48 int main()
49 {
50     cout<<Completeknapsack()<<endl;52     return 1;
53 }

  2.完全背包优化:可以利用贪心的思想,先尽量取出cost[i]/weight[i]高的物品装进背包中,等到装不下时在装质量稍小一点的,一次类推,代码回头补上

  3.直接利用多重背包

  完全背包的物品可以取无限件,根据背包的总容量V和第i件物品的总重量Weight[i],可知,背包中最多装入V/Weight[i](向下取整)件该物品。因此可以直接改变第i件物品的总个数,使之达到V/Weight[i](向下取整)件,之后直接利用01背包的思路进行操作即可。

  举例:物品个数N = 3,背包容量为V = 5。

  拆分之前的物品序列:

                                       技术分享

  拆分之后的物品序列:

                 技术分享

根据上述思想:在背包的最大容量(5)中,最多可以装入1件物品一,因此不用扩展物品一。最多可以装入2件物品二,因此可以扩展一件物品二。同理,可以扩展一件物品三。

 

 

 

 

 

背包问题九讲:http://love-oriented.com/pack/Index.html

背包之01背包、完全背包、多重背包详解 :http://www.wutianqi.com/?p=539

背包问题九讲笔记_01背包:http://blog.csdn.net/insistgogo/article/details/8579597

背包问题九讲笔记_完全背包:http://blog.csdn.net/insistgogo/article/details/11081025

背包问题九讲笔记_多重背包:http://blog.csdn.net/insistgogo/article/details/11176693

01背包、完全背包、多重背包:http://blog.csdn.net/wzy_1988/article/details/12260343

背包问题详解

标签:

原文地址:http://www.cnblogs.com/a1225234/p/4693251.html

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