背包复习

Posted milky-w

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包复习相关的知识,希望对你有一定的参考价值。

01背包

问题描述

已知:有一个容量为 V 的背包和 N 件物品,第 i 件物品的重量是 weight[ i ],收益是 cost[ i ]。

限制:每种物品只有一件,可以选择放或者不放

问题:在不超过背包容量的情况下,最多能获得多少价值或收益

相似问题:在恰好装满背包的情况下,最多能获得多少价值或收益

这里,我们先讨论在不超过背包容量的情况下,最多能获得多少价值或收益。

基本思路

01背包的特点:每种物品只有一件,可以选择放或者不放

状态转移方程:f[ i ][ v ] = max( f[ i - 1 ][ v ] , f[ i - 1 ][ v - weight[ i ] ] + cost[ i ] )

代码

技术分享图片
 1 #include <iostream>  
 2 using namespace std;  
 3   
 4 const int N = 3;//物品个数  
 5 const int V = 5;//背包最大容量  
 6 int weight[N + 1] = {0,3,2,2};//物品重量  
 7 int value[N + 1] = {0,5,10,20};//物品价值  
 8   
 9 int f[N + 1][V + 1] = {{0}};  
10   
11 int Max(int x,int y)  
12 {  
13     return x > y ? x : y;  
14 }  
15   
16 /* 
17 目标:在不超过背包容量的情况下,最多能获得多少价值 
18  
19 子问题状态:f[i][j]:表示前i件物品放入容量为j的背包得到的最大价值 
20  
21 状态转移方程:f[i][j] = max{f[i - 1][j],f[i - 1][j - weight[i]] + value[i]} 
22  
23 初始化:f数组全设置为0 
24 */  
25 int Knapsack()  
26 {  
27     //初始化  
28     memset(f,0,sizeof(f));  
29     //递推  
30     for (int i = 1;i <= N;i++) //枚举物品  
31     {  
32         for (int j = 0;j <= V;j++) //枚举背包容量  
33         {  
34             f[i][j] = f[i - 1][j];  
35             if (j >= weight[i])  
36             {  
37                 f[i][j] = Max(f[i - 1][j],f[i - 1][j - weight[i]] + value[i]);  
38             }  
39         }  
40     }  
41     return f[N][V];  
42 }  
43   
44 int main()  
45 {  
46     cout<<Knapsack()<<endl;  
47     return 1;  
48 }
二维数组
技术分享图片
 1 #include <iostream>  
 2 using namespace std;  
 3   
 4 const int N = 3;//物品个数  
 5 const int V = 5;//背包最大容量  
 6 int weight[N + 1] = {0,3,2,2};//物品重量  
 7 int value[N + 1] = {0,5,10,20};//物品价值  
 8   
 9 int f[V + 1] = {0};  
10   
11 int Max(int x,int y)  
12 {  
13     return x > y ? x : y;  
14 }  
15   
16 /* 
17 目标:在不超过背包容量的情况下,最多能获得多少价值 
18  
19 子问题状态:f[j]:表示前i件物品放入容量为j的背包得到的最大价值 
20  
21 状态转移方程:f[j] = max{f[j],f[j - weight[i]] + value[i]} 
22  
23 初始化:f数组全设置为0 
24 */  
25 int Knapsack()  
26 {  
27     //初始化  
28     memset(f,0,sizeof(f));  
29     //递推  
30     for (int i = 1;i <= N;i++) //枚举物品  
31     {  
32         for (int j = V;j >= weight[i];j--) //枚举背包容量,防越界,j下限为 weight[i]  
33         {  
34             f[j] = Max(f[j],f[j - weight[i]] + value[i]);  
35         }  
36     }  
37     return f[V];  
38 }  
39   
40 int main()  
41 {  
42     cout<<Knapsack()<<endl;   
43     return 1;  
44 }
一维数组

 

恰好装满

使用二维数组f[i][v]存储中间状态,其中第一维表示物品,第二维表示背包容量;初始化时,除了f[i][0] = 0(第一列)外,其他全为负无穷。

技术分享图片
 1 #include <iostream>  
 2 using namespace std;  
 3   
 4 const int MinNum = 0x80000000;  
 5   
 6 const int N = 3;//物品个数  
 7 const int V = 5;//背包最大容量  
 8 int weight[N + 1] = {0,3,2,2};//物品重量  
 9 int value[N + 1] = {0,5,10,20};//物品价值  
10   
11 int f[N + 1][V + 1] = {{0}};  
12   
13 int Max(int x,int y)  
14 {  
15     return x > y ? x : y;  
16 }  
17   
18 /* 
19 目标:在恰好装满背包的情况下,最多能获得多少价值 
20  
21 子问题状态:f[i][j]:表示前i件物品放入容量为j的背包得到的最大价值 
22  
23 状态转移方程:f[i][j] = max{f[i - 1][j],f[i - 1][j - weight[i]] + value[i]} 
24  
25 初始化:f数组全设置为0 
26 */  
27 int Knapsack()  
28 {  
29     //初始化  
30     for (int i = 0;i <= N;i++) //枚举物品  
31     {  
32         for (int j = 0;j <= V;j++) //枚举背包容量  
33         {  
34             f[i][j] = MinNum;  
35         }  
36     }  
37     for (int i = 0;i <= N;i++)  
38     {  
39         f[i][0] = 0;//背包容量为0时为合法状态  
40     }  
41     //递推  
42     for (int i = 1;i <= N;i++) //枚举物品  
43     {  
44         for (int j = 1;j <= V;j++) //枚举背包容量  
45         {  
46             f[i][j] = f[i - 1][j];  
47             if (j >= weight[i])  
48             {  
49                 f[i][j] = Max(f[i - 1][j],f[i - 1][j - weight[i]] + value[i]);  
50             }  
51         }  
52     }  
53     return f[N][V];  
54 }  
55   
56 int main()  
57 {  
58     cout<<Knapsack()<<endl;//输出25   
59     return 1;  
60 }
二维数组
技术分享图片
 1 #include <iostream>  
 2 using namespace std;  
 3   
 4 const int MinNum = 0x80000000;//int最小的数  
 5   
 6 const int N = 3;//物品个数  
 7 const int V = 5;//背包最大容量  
 8 int weight[N + 1] = {0,3,2,2};//物品重量  
 9 int value[N + 1] = {0,5,10,20};//物品价值  
10   
11 int f[V + 1] = {0};  
12   
13 int Max(int x,int y)  
14 {  
15     return x > y ? x : y;  
16 }  
17   
18 /* 
19 目标:在恰好装满背包容量的情况下,最多能获得多少价值 
20  
21 子问题状态:f[j]:表示前i件物品放入容量为j的背包得到的最大价值 
22  
23 状态转移方程:f[j] = max{f[j],f[j - weight[i]] + value[i]} 
24  
25 初始化:f数组全设置为0 
26 */  
27 int Knapsack()  
28 {  
29     //初始化  
30     for (int i = 0;i <= V;i++)  
31     {  
32         f[i] = MinNum;  
33     }  
34     f[0] = 0;//只有背包容量为0时才是合法状态,由合法状态组成的结果才是合法的  
35   
36     //递推  
37     for (int i = 1;i <= N;i++) //枚举物品  
38     {  
39         for (int j = V;j >= weight[i];j--) //枚举背包容量,防越界,j下限为 weight[i]  
40         {  
41             f[j] = Max(f[j],f[j - weight[i]] + value[i]);  
42         }  
43     }  
44     return f[V];  
45 }  
46   
47 int main()  
48 {  
49     cout<<Knapsack()<<endl;//输出25   
50     return 1;  
51 }
一维数组

 

完全背包

问题描述

已知:有一个容量为 V 的背包和 N 件物品,第 i 件物品的重量是 weight[ i ],收益是 cost[ i ]。

条件:每种物品都有无限件,能放多少就放多少。

问题:在不超过背包容量的情况下,最多能获得多少价值或收益。

基本思路

方法有拆分物品、二进制转换等,但都太慢。

只需将逆序枚举的01背包改成顺序枚举即可。

代码

技术分享图片
 1 #include <iostream>  
 2 #include <vector>  
 3 #include <assert.h>  
 4 using namespace std;  
 5 const int N = 3;  
 6 const int V = 5;//5  
 7 int weight[N + 1] = {0,3,2,2};  
 8 int Value[N + 1] = {0,5,10,20};  
 9   
10 int f[N + 1][V + 1] = {0};  
11   
12 int Completeknapsack()  
13 {  
14     //初始化  
15     for (int i = 0;i <= N;i++)  
16     {  
17         f[i][0] = 0;  
18     }  
19     for (int v = 0;v <= V;v++)  
20     {  
21         f[0][v] = 0;  
22     }  
23     for (int i = 1;i <= N;i++)  
24     {  
25         for (int v = weight[i];v <= V;v++)  
26         {  
27             f[i][v] = max(f[i - 1][v],f[i][v - weight[i]] + Value[i]);  
28         }  
29     }  
30     return f[N][V];  
31 }  
32   
33 int main()  
34 {  
35     cout<<Completeknapsack()<<endl;   
36     return 1;  
37 }
二维数组
技术分享图片
 1 include <iostream>  
 2 using namespace std;  
 3 const int N = 3;  
 4 const int V = 5;//5  
 5 int weight[N + 1] = {0,3,2,2};  
 6 int Value[N + 1] = {0,5,10,20};  
 7   
 8 int f[V + 1] = {0};  
 9   
10 int Completeknapsack()  
11 {  
12     f[0] = 0;  
13     for (int i = 1;i <= N;i++)  
14     {  
15         for (int v = weight[i];v <= V;v++)  
16         {  
17             f[v] = max(f[v],f[v - weight[i]] + Value[i]);  
18         }  
19     }  
20     return f[V];  
21 }  
22 int main()  
23 {  
24     cout<<Completeknapsack()<<endl;  
25     return 1;  
26 }
一维数组

 


from 远航之曲

 

以上是关于背包复习的主要内容,如果未能解决你的问题,请参考以下文章

codevs 3269 混合背包(复习混合背包)

01背包与完全背包(dp复习)

01背包问题复习

01背包问题复习

01背包问题复习

01背包问题复习