【01背包】滚动数组优化实现一维01背包DP(对比朴素写法)

01背包

代码

背包问题的滚动数组优化版本建议在完全弄懂了普通的二维01背包问题后再进行食用,不然会出现消化不良的症状…

我们可以将背包问题中DP数组的下标看作成两个集合

下面对比两种不同实现方法的区别:

  • 朴素二维DP版本

    • 使用dp[不超过i的物品集合][不超过j的背包集合]
    • 我们会发现,每次使用的[不超过第i个物品的集合]只会是ii-1,再往前的集合在后续的计算都不会被使用,所以可以采用滚动数组的思想,不断的更新一个一维数组来达到相同的目的。
    • 同时,我们每次会对每一个物品寻找所有[不超过j的背包的集合],如果背包放不下这个物品,直接继承没有放i物品的状态即可,也就是[不超过i-1位物品]的集合。
    • 同时这里和优化版本的区别还在于遍历顺序,朴素版本不用考虑遍历顺序,但是优化版本需要注意。
    #include <iostream>
    using namespace std;
    // DP-normal-way
    
    const int N = 1010;
    int n, m;		//n件物品 m容量的背包 
    int v[N], w[N]; //每件物品的体积 价值 
    int f[N][N];	//f[i][j]不超过第i件物品 背包容量不超过j 
    
    /*
    4 5
    1 2
    2 4
    3 4
    4 5
    */
    
    int main() {
    	cin >> n >> m;
    	
    	for (int i = 1; i <= n; i++) {
    		cin >> v[i] >> w[i];			//输入体积 价值 
    	}
    	//f[0][0~m]默认为零,无需进行初始化
    	
    	for (int i = 1; i <= n; i++) {
    		for (int j = 1; j <= m; j++) {
    			if (j >= v[i]) f[i][j] = max(f[i-1][j], w[i] + f[i-1][j-v[i]]);
    			else f[i][j] = f[i-1][j];
    		}
    	} 	
    	
    	cout << f[n][m] << endl;	
    }
    
  • 滚动数组优化版本 --> 一维DP(01背包问题终极写法)

    • dp[i][j]-->dp[j]删掉了i这个集合,相当于现在每次只存放了前一个物品的[背包不超过j]的最大值。
      • 比如第一次,dp[]存放的是不超过第一个物品的[背包不超过j] 的最大值。
      • 第二次在第一次的基础上进行更新,这里需要注意背包集合的遍历顺序,需要思考如果还是正序遍历会带来什么影响?
      • 没错,因为每次都要利用到之前的[背包不超过j]的集合,如果正序遍历,那么就会从小的背包开始更新,那么就会把上一次的背包最大值覆盖掉,遍历到后面,j大起来了,要使用上一次也就是[物品不超过i-1][背包不超过j]的集合来进行更新就会碰到滚动数组数据被覆盖了的问题。
      • 所以,需要注意的就是,要从大的背包开始遍历j,这样就可以避免dp[背包容量<j]被覆盖掉,进行滚动的更新。
    #include <iostream>
    // 01背包1维写法 
    
    const int N = 10010;
    int n, m;	//物品个数  背包容量
    int v[N], w[N];	//每个物品的:体积 价值
    int dp[N];	//优化前:不超过i的物品的体积和不超过j的背包 --> 优化后: 不超过i件物品  -->最大价值 
    /*输入数据不变: 
    4 5
    1 2
    2 4
    3 4
    4 5
    */
    using namespace std;
    
    int main() {
    	cin >> n >> m;
    	for (int i = 0; i < n; i++) {
    		cin >> v[i] >> w[i];
    	}
    	for (int i = 1; i <= n; i++) {
    		for (int j = m; j >= v[i]; j-- ) {
    			dp[j] = max(dp[j], dp[j-v[i]] + w[i]);
    		}
    	}
    	cout << dp[m] << endl;
    }
    
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通过空间优化版本的0-1背包问题解法,可以利用一维数组进行优化。这是因为在0-1背包问题中,每个物品只能选择放入背包一次或不放入,所以在计算第i个物品放入容量为j的背包的最大价值时,只需要考虑前i-1个物品放入容量为j的背包的最大价值和前i-1个物品放入容量为j-vol[i的背包的最大价值加上第i个物品的价值,取两者的较大值即可。通过这种方式,可以将二维数组转化为一维数组实现空间优化。 具体的实现方法如下: 1. 创建一个一维数组dp,长度为背包的容量V+1,用于存储每个容量下的最大价值。 2. 遍历每个物品,从最后一个物品开始倒序遍历。 3. 对于当前遍历到的物品i,在容量为j的背包中,判断是否能够放入该物品: - 若当前容量j小于物品i的体积vol[i,则无法放入,最大价值保持不变,即dp[j = dp[j。 - 若当前容量j大于等于物品i的体积vol[i,则可以选择放入该物品或不放入该物品,取两者的较大值作为最大价值,即dp[j = max(dp[j], dp[j-vol[i]] + val[i])。 4. 完成遍历后,最终的最大价值即为dp[V。 这样,通过一维数组的空间优化,可以在0-1背包问题中节省空间,并且得到相同的最优解。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [leetcode 背包类问题](https://blog.csdn.net/u014034683/article/details/114481074)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [0-1背包问题的一维数组优化解析](https://blog.csdn.net/hnjzsyjyj/article/details/126071689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值