背包问题【01背包扫盲】【动规五步法】

背包问题-01背包扫盲【动规五步法】

0 - 前言

本文针对01背包问题,主要参考【代码随想录】大佬的背包九讲,上一个链接。本文中示范用例与代码取自大佬链接中。

参考:动态规划:关于01背包问题,你该了解这些!

1 - 什么是01背包

物品数量为N,每个物品的重量为weight[i],i∈[1, N],对应的物品价值为value[i], i∈[1, N],每件物品只有一件,问题是:将哪些物品放进背包后,背包中的价值总和最大?

2 - 动规五步法解决背包

1、确定dp数组与下标含义

dp[i] [j] 表示从下标[0-i]内的物品任意取,存放进容量为j的背包后,最大价值总和是多少。也就是,行索引i用户来遍历物品,列索引j用来遍历背包容量。遍历物品能理解,那么为什么要遍历背包容量呢?这是因为需要一点点增加背包容量,直到容量为j,表明是有状态转移存在的,因此才可以用动态规划来解决。

dp[i] [j]数组形式如下:

dp[i][j]	
			0	1	2	3	4	5
物品0:
物品1:
物品2:

2、确定递推公式

一般二维dp数组会从行索引与列索引两个方向上求出状态递推。

  • 先来看行索引:i的上一状态应该是i-1。在不放物品i的时候的dp[i][j] = dp[i-1][j],表示j背包直接从[0~ i-1]内选取物品后的最大价值。dp[i][j] = dp[i-1][j]的真正含义应该是:j背包中,不管有没有空间放weight[i],都不放i
  • 再来看列索引:这里j的上一状态并不是j-1,这是由背包问题的特殊场景造成的,因为行索引的情况已经将**不放i的情况解决完了,那么列索引只能解决i**的情况,换言之,j的上一状态一定要预留出weight[i]的空间保证j背包一定能放下i。那么j的上一状态应该是什么呢?应该是j-weight[i]。所以从列索引角度,dp[i-1][j-weight[i]] + value[i]就是背包中放物品i的最大价值。其中,行索引之所以不是i而是i-1,是要保证j的上一状态没有放过i

那么递推公式显而易见了,dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]])

其实不推导,直接解读递推公式的话,也是比较容易理解的。dp[i-1][j]代表:不将物品i放入背包的最大价值。dp[i-1][j-weight[i]] + value[i]表示:将物品i放进背包之后的最大价值。两者之中的最大值就是dp[i][j]

3、dp数组的初始化

二维dp数组初始化就是看两条边。

  • dp[i][0]:即背包容量为0的时候,此时放不进去物品,dp[i][0] = 0
  • dp[0][j]:遍历背包容量来存放物品0,只有两种情况,放得下物品0(dp[0][j]=value[0])和放不下(dp[0][j]=0)。

4 、确定遍历顺序

可以先遍历物品i(dp数组行索引),再遍历背包容量j(dp数组列索引)

5、举例推导dp数组

假设物品信息如下

			重量		价值
物品0			1		 15
物品1			3		 20
物品2			4		 30
dp[i][j]	
			 0	 1	 2	 3	 4
物品00   15  15  15  15 
物品10   15  15  20  35  
物品20   15  15  20  35

完整代码如下:

void test_2_wei_bag_problem1() {
    
    
    vector<int> weight = {
    
    1, 3, 4};
    vector<int> value = {
    
    15, 20, 30};
    int bagWeight = 4;

    // 二维数组
    vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1, 0));

    // 初始化 
    for (int j = 0; j <= bagWeight; ++j) {
    
    
        if (weight[0] <= j)
        	dp[0][j] = value[0];
    }

    // weight数组的大小 就是物品个数
    for(int i = 1; i < weight.size(); i++) {
    
     // 遍历物品
        for(int j = 0; j <= bagWeight; j++) {
    
     // 遍历背包容量
            if (j < weight[i]) 
                dp[i][j] = dp[i - 1][j];
            else 
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

        }
    }

    cout << dp[weight.size() - 1][bagWeight] << endl;
}

int main() {
    
    
    test_2_wei_bag_problem1();
}

猜你喜欢

转载自blog.csdn.net/weixin_44484715/article/details/115109428