背包复习
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 远航之曲
以上是关于背包复习的主要内容,如果未能解决你的问题,请参考以下文章