01背包

01背包:

物品数量有限,一件物品只有两个状态:取or不取;(所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是$o(2^n)$,这里的n表示物品数量。)

二维dp:

背包问题,使用二维数组,即dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

 

有两个方向推出来dp[i][j]:

  • 不放物品i:由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。
  • 放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] 。

递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])。

初始化,一定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱。

  • 从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。
  • 且i 是由 i-1 推导出来,那么i为0的时候就一定要初始化。dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。

    j < weight[0]:dp[0][j] 应该是 0,因为背包容量比编号0的物品重量还小。

    j >= weight[0]:dp[0][j] 应该是value[0],因为背包容量放足够放编号0物品。

 

 完整代码如下:

 1 void test_2_wei_bag_problem1() {
 2     vector<int> weight = {1, 3, 4};
 3     vector<int> value = {15, 20, 30};
 4     int bagweight = 4;
 5 
 6     // 二维数组
 7     vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
 8 
 9     // 初始化
10     for (int j = weight[0]; j <= bagweight; j++) {
11         dp[0][j] = value[0];
12     }
13 
14     // weight数组的大小 就是物品个数
15     for(int i = 1; i < weight.size(); i++) { // 遍历物品
16         for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
17             if (j < weight[i]) dp[i][j] = dp[i - 1][j];
18             else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
19 
20         }
21     }
22 
23     cout << dp[weight.size() - 1][bagweight] << endl;
24 }
25 
26 int main() {
27     test_2_wei_bag_problem1();
28 }

 

  

 

posted @ 2022-05-10 11:40  Siu_Miner  阅读(46)  评论(0)    收藏  举报