背包复习

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 2
  2 3
  3 4
  4 5
  5 6
  6 7
  7 8
  8 9
  9 10
 10 11
 11 12
 12 13
 13 14
 14 15
 15 16
 16 17
 17 18
 18 19
 19 20
 20 21
 21 22
 22 23
 23 24
 24 25
 25 26
 26 27
 27 28
 28 29
 29 30
 30 31
 31 32
 32 33
 33 34
 34 35
 35 36
 36 37
 37 38
 38 39
 39 40
 40 41
 41 42
 42 43
 43 44
 44 45
 45 46
 46 47
 47 48
 48 49
 49 50
 50 51
 51 52
 52 53
 53 54
 54 55
 55 56
 56 57
 57 58
 58 59
 59 60
 60 #include <iostream>  
 61 using namespace std;  
 62   
 63 const int MinNum = 0x80000000;  
 64   
 65 const int N = 3;//物品个数  
 66 const int V = 5;//背包最大容量  
 67 int weight[N + 1] = {0,3,2,2};//物品重量  
 68 int value[N + 1] = {0,5,10,20};//物品价值  
 69   
 70 int f[N + 1][V + 1] = {{0}};  
 71   
 72 int Max(int x,int y)  
 73 {  
 74     return x > y ? x : y;  
 75 }  
 76   
 77 /* 
 78 目标:在恰好装满背包的情况下,最多能获得多少价值 
 79  
 80 子问题状态:f[i][j]:表示前i件物品放入容量为j的背包得到的最大价值 
 81  
 82 状态转移方程:f[i][j] = max{f[i - 1][j],f[i - 1][j - weight[i]] + value[i]} 
 83  
 84 初始化:f数组全设置为0 
 85 */  
 86 int Knapsack()  
 87 {  
 88     //初始化  
 89     for (int i = 0;i <= N;i++) //枚举物品  
 90     {  
 91         for (int j = 0;j <= V;j++) //枚举背包容量  
 92         {  
 93             f[i][j] = MinNum;  
 94         }  
 95     }  
 96     for (int i = 0;i <= N;i++)  
 97     {  
 98         f[i][0] = 0;//背包容量为0时为合法状态  
 99     }  
100     //递推  
101     for (int i = 1;i <= N;i++) //枚举物品  
102     {  
103         for (int j = 1;j <= V;j++) //枚举背包容量  
104         {  
105             f[i][j] = f[i - 1][j];  
106             if (j >= weight[i])  
107             {  
108                 f[i][j] = Max(f[i - 1][j],f[i - 1][j - weight[i]] + value[i]);  
109             }  
110         }  
111     }  
112     return f[N][V];  
113 }  
114   
115 int main()  
116 {  
117     cout<<Knapsack()<<endl;//输出25   
118     return 1;  
119 }
二维数组
 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 }
一维数组

猜你喜欢

转载自www.cnblogs.com/milky-w/p/9039018.html