01背包(就地滚动)

本文详细介绍了01背包问题的解决方法,特别是采用就地滚动数组优化的经典案例。通过一个具体的例子,即选择最佳魅力手镯饰品组合的问题,展示了如何在限定重量下达到价值的最大化。文章提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<span style="color:#3333ff;">/*
__________________________________________________________________________________________________
*     copyright:   Grant Yuan                                                                     *
*     algorithm:   01背包(就地滚动)                                                             *
*     time     :   2014.7.18                                                                      *
*     declare  :   题目中说N最大是3400多,但是一开始开了5000内存还是运行时错误,后来直接改了50000 *                                                       *                                                                                                 *
*_________________________________________________________________________________________________*</span>
<span style="color:#3333ff;">
I - 01背包(就地滚动)
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Submit
 
Status
Description
Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi ≤ 400), a 'desirability' factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).

Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.

Input
* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Line i+1 describes charm i with two space-separated integers: Wi and Di

Output
* Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints

Sample Input
4 6
1 4
2 6
3 12
2 7
Sample Output
23
*/

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

int w[50001];
int p[50001];
int sum;
int n;
int dp[50001];

int main()
{
	cin>>n>>sum;
	for(int i=0;i<n;i++)
		cin>>w[i]>>p[i];
	memset(dp,0,sizeof(dp));
	for(int i=0;i<n;i++)
	   for(int j=sum;j>=w[i];j--)
	    {
		dp[j]=max(dp[j],dp[j-w[i]]+p[i]);
	     }
	cout<<dp[sum]<<endl;
	return 0;
}
</span>

转载于:https://www.cnblogs.com/codeyuan/p/4254499.html

### 滚动数组在01背包问题中的实现与优化 #### 一、滚动数组的基本原理 在传统的动态规划解决01背包问题时,通常会使用二维数组`dp[i][j]`表示前`i`个物品放入容量为`j`的背包所能获得的最大价值。然而,这种方法的空间复杂度较,为`O(nW)`,其中`n`是物品数量,`W`是背包容量。通过观察状态转移方程`dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])`[^3],可以发现当前状态`dp[i][j]`仅依赖于上一行的状态`dp[i-1][...]`,因此可以通过滚动数组将二维数组优化为一维数组。 #### 二、滚动数组的优化过程 1. **空间优化** 使用一维数组`dp[j]`代替二维数组`dp[i][j]`,其中`dp[j]`表示容量为`j`的背包所能容纳的最大价值。通过逆序遍历背包容量`j`(从`W`到`w[i]`),可以确保每个物品只被考虑一次,避免重复计算。 这种逆序遍历的方式保证了在更新`dp[j]`时,使用的仍然是未更新的`dp[j-w[i]]`值,从而正确模拟了二维数组的状态转移过程[^4]。 2. **代码实现** 下面是一个基于滚动数组优化的01背包问题的Java实现: ```java public class Knapsack { public static int knapsack(int[] weights, int[] values, int capacity) { int n = weights.length; int[] dp = new int[capacity + 1]; for (int i = 0; i < n; i++) { for (int j = capacity; j >= weights[i]; j--) { dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]); } } return dp[capacity]; } public static void main(String[] args) { int[] weights = {2, 3, 4}; int[] values = {3, 4, 5}; int capacity = 5; System.out.println("最大价值: " + knapsack(weights, values, capacity)); } } ``` 3. **时间复杂度与空间复杂度** - 时间复杂度:仍为`O(nW)`,因为需要对每个物品和每个背包容量进行遍历。 - 空间复杂度:由`O(nW)`降低至`O(W)`,显著减少了内存消耗[^2]。 #### 三、滚动数组的关键点 - **逆序遍历**:为了防止在更新`dp[j]`时覆盖掉尚未使用的`dp[j-w[i]]`值,必须从大到小遍历背包容量。如果正序遍历,则会导致同一物品被多次放入背包中,违背01背包问题的规则[^4]。 - **边界条件**:当背包容量`j`小于当前物品重量`w[i]`时,无法放入该物品,因此无需更新`dp[j]`[^3]。 #### 四、滚动数组的应用场景 滚动数组仅适用于01背包问题,还可以推广到其他动态规划问题中,只要满足当前状态仅依赖于少数几个之前状态的情况。例如,在某些矩阵路径问题或字符串匹配问题中,也可以通过类似的方法减少空间开销[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值