01背包问题详解
创始人
2024-05-09 07:12:16
0

目录

1.1二维dp数组

1.2一维dp数组改进

1.3相关例题

1.3.1分割等和子集

1.3.2一和零


1.1二维dp数组

概述:背包的最大重量是固定的,物品的数量,重量也是固定的,并且物品只能放一次,可以选择放或者不放,最后要保证背包里面物品的最大价值。

例如:下面假设背包的最大重量是4.

 解释:dp[i][j]的含义:从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

可以从两个方向去推导dp[i][j],放当前物品或者不放当前物品。

由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]
由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]且不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值,所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

开辟一个二维数组

 当背包的容量为0和物品数量为0时,背包的价值都是0.

 可以尝试先遍历物,1,可以认为当前只有一个物品,背包的容量为1-4,后面在去遍历物品2,背包的容量也是从1-4。例如:

 完整代码:

vector weight = { 1, 3, 4 };
vector value = { 15, 20, 30 };
int bagWeight = 4;// 二维数组,全初始化为0
vector> dp(weight.size() + 1, vector(bagWeight + 1, 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]);}
}

1.2一维dp数组改进

思路:

在使用二维数组的时候,递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

其实可以发现如果把dp[i - 1]那一层拷贝到dp[i]上,表达式完全可以是:dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);把dp[i - 1]这一层拷贝到dp[i]上,不如只用一个一维数组了,只用dp[j](一维数组,也可以理解是一个滚动数组)。

确定dp数组的定义:
在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

一维dp数组的递推公式

dp[j]可以通过dp[j - weight[j]]推导出来,dp[j - weight[i]]表示容量为j - weight[i]的背包所背的最大价值。dp[j - weight[i]] + value[i] 表示 容量为 j - 物品i重量 的背包 加上 物品i的价值。(也就是容量为j的背包,放入物品i了之后的价值)

dp[j]有两个选择,一个是取自己dp[j],一个是取dp[j - weight[i]] + value[i],取最大值,递归公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

假设也是先遍历物品,再去遍历背包。

例如:

 在一维数组中,为了确保每个物品只能放入一次,遍历背包时,应该先去遍历背包的容量。例如:

 代码:

for (int i = 0; i < weight.size(); i++) // 遍历物品
{                                 for (int j = bagWeight; j >= weight[i]; j--) {dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); // 遍历背包容量}
}

1.3相关例题

1.3.1分割等和子集

问题描述:给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

思路:使这两个子集的元素相等,也就是让子集的和为数组和的一半。其实可以认为子集和就是背包的最大容量,也是最大价值。问题等效于能否从数组中挑选若干个元素,使得元素总和等于所有元素总和的一半。也就是判断该背包装满后,最大容量装满后的价值是否恰好等于最大价值。

代码示例:

class Solution {
public:bool canPartition(vector& nums) {int sum=0;for(int i=0;i>dp(nums.size()+1,vector(sum+1,0));for(int i=1;i<=nums.size();i++){for(int j=1;j<=sum;j++)   //nums[i-1]为第i个物品{if(j

一维dp数组改进:

class Solution {
public:bool canPartition(vector& nums) {int sum = 0;for (int i = 0; i < nums.size(); i++){sum += nums[i];}if (sum % 2 == 1) return false;int target = sum / 2;vector dp(target + 1, 0);// 开始 01背包for (int i = 0; i < nums.size(); i++) {for (int j = target; j >= nums[i]; j--) { dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);}}if (dp[target] == target)return true;return false;}
};

1.3.2一和零

问题描述:

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

这也是一道01背包问题,元素的个数是确定的,背包的容量也是确定的,只不过该背包的容量有两个维度罢了。本质就是求背包放满后,可以放入的元素个数最多是多少。

class Solution {
public:int findMaxForm(vector& strs, int m, int n) {//m个0,n个1vector> v(m+1,vector(n+1,0));for(auto s:strs){  int p1=0;int p0=0;for(auto ch: s)   //先遍历物品{if(ch=='0')p0++;elsep1++;}                 for(int i=1;i<=m;i++) /后遍历背包容量,背包容量,用一个二维数组表示{for(int j=1;j<=n;j++){if(i>p0&&j>p1)  //说明能放下该物品{v[i][j]=max(v[i][j],v[i-p0][j-p1]+1);}}}}return v[m][n];}
};

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...