代码随想录算法训练营第四十二天| 01背包问题 二维,01背包问题 一维,416. 分割等和子集

ops/2024/9/23 11:01:06/

目录

题目链接: 01背包问题 二维

思路

代码

题目链接:01背包问题 一维

思路

代码

题目链接: 416. 分割等和子集

思路

代码

总结


题目链接:01背包问题 二维

思路

        ①dp数组,物品从下标0到i的物品中任取,然后放进容量为j的背包里,此时最大的价值

        ②递推公式,到第i个物品时有两个选择,放或者不放。如果不放,最大价值就是dp[i-1][j],说明第i个物品太大了放不下,价值还是和i-1的状态一样;如果放,最大价值就是i-1时的价值加上value[i],即dp[i-1][j-wight[i]]+value[i]。也就是说当前dp[i][j]可以由这两个状态推导而来,因为要取最大价值,所以取这两个值中的最大值

        ③dp数组初始化,由递推公式可知,dp数组当前值可由左上角和正上方两个方向推导而来, 所以只需要初始化第一列和第一行即可由递推公式得到整个二维dp数组。当背包容量为0时,放不了东西,所以这一列初始化为0;下标为物品0时,如果背包容量足够就将其初始化为物品0的价值,如果放不下就初始化为0

        ④遍历顺序,由递推公式可知,只要有左上角和上方的值即可推导当前值,所以先遍历行或者列,或者说先遍历物品或者背包都可以

        ⑤推导dp数组

代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int m,n;//m为物品个数,n为背包空间
void solve(){vector<int> weight(m,0);//物品重量vector<int> value(m,0);//物品价值vector<vector<int>> dp(m,vector<int>(n+1,0));//dp数组//输入重量和价值for(int i = 0; i < m; i++){cin>>weight[i];}for(int i = 0; i < m; i++){cin>>value[i];}//当第一个物品的重量小于背包空间时//此时dp赋值为该物品的valuefor(int j = weight[0]; j <= n; j++){dp[0][j] = value[0];}//遍历背包for(int j = 0; j <= n; j++){//遍历物品,物品从1到ifor(int i = 1; i < m; i++){if(weight[i] > j) //装不下时,价值与遍历到上一个物品时一样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[m-1][n]<<endl;}int main(){while(cin>>m>>n){solve();}return 0;
}

题目链接:01背包问题 一维

思路

        ①dp数组,容量为j的背包,能装的物品价值最大为dp[j]

        ②递推公式,与二维类似,只不过用了一维的滚动数组。此时背包空间为j,有两个选择:装不下当前物品,则此时背包的价值与遍历上一个物品时一样,也就是dp[j] = dp[j-weight[i]];能装下时,有两种情况,装完后价值比之前大,装完后价值比之前小,肯定是二者选最大。装之前,dp[j] = dp[j-weight[i]],装之后,dp[j] = dp[j-weight[i]] + value[i]。

        ③dp数组初始化,根据递推公式可知背包空间为0时装不了物品,所以价值为0即dp[0] = 0,往后遍历时会进行更新,所以其他位置先初始化为0即可。

        ④遍历顺序,先物品,后背包,且背包倒序遍历,从空间最大往前遍历。因为是先遍历物品,如果背包正序遍历,则物品i可能会被重复放入。

        ⑤推导dp数组

代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;//一维dp数组
int m,n;//m为物品种类,n为背包容量
void solve(){vector<int> weight(m,0);vector<int> value(m,0);//dp[n]的意义是背包容量为n的时候,所装物品的最大价值为dp[n]//因为dp数组从0开始,所以dp数组的大小为n+1vector<int> dp(n+1,0);//输入物品信息,重量和价值for(int i = 0; i < m; i++){cin>>weight[i];}for(int i = 0; i < m; i++){cin>>value[i];}//遍历顺序,先物品,后背包,其背包倒序遍历//由于dp数组大小有限,并不会保存上一层的信息//所以要先遍历物品,把当前物品处理完再进行下一层//背包倒序遍历是防止同一物品被多次装入背包for(int i = 0; i < m; i++){//如果能装下才对dp数组当前位置进行更新for(int j = n; j >=weight[i]; j--){dp[j] = max(dp[j],dp[j-weight[i]]+value[i]);}}cout<<dp[n]<<endl;
}int main(){while(cin>>m>>n){solve();}return 0;
}

题目链接:416. 分割等和子集

思路

        将该题归类为01背包问题

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。

        ①dp数组,容量为j的背包所装物品的最大价值为dp[j],本题所给的数组既是重量也是价值

        ②递推公式,dp[j] = max[dp[j], dp[j-nums[i]]+nums[i]]

        ③dp数组初始化,本题所给数组中的数都是正整数,所以初始化为0即可

        ④遍历顺序,滚动数组,先物品后背包,背包倒序

        ⑤推导dp数组

代码

class Solution {
public:bool canPartition(vector<int>& nums) {// 计算数组中所有元素之和int sum = 0;for (int i = 0; i < nums.size(); i++) {sum += nums[i];}// 如果和为奇数,则不可能分隔,因为都是数组中都为正整数if (sum % 2 == 1)return false;// target为背包的容量int target = sum / 2;vector<int> dp(target + 1, 0); // 定义dp数组// 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;}
};

总结

        ①01背包问题,m个物品,有各自的重量和价值,背包容量为n,将物品装入到背包里,使得背包中物品的价值总和最大

        ②选择背包大小为dp数组,dp[j]的含义是背包容量为j时装入物品的最大价值

        ③再遍历dp数组时,每次都有两个选择,装与不装。当容量不足时就不装,价值与上一状态一样;当容量足够时,装入当前物品有一个价值,上一状态也有一个价值,取最大值

        ④416.分割等和子集竟然能用01背包解决,属实是意想不到

        ⑤刚开始接触背包问题,很多细节没有掌握,需要复习


http://www.ppmy.cn/ops/31715.html

相关文章

Spring扩展点(一)Bean生命周期扩展点

Bean生命周期扩展点 影响多个Bean的实例化InstantiationAwareBeanPostProcessorBeanPostProcessor 影响单个Bean的实例化纯粹的生命周期回调函数InitializingBean&#xff08;BeanPostProcessor 的before和after之间调用&#xff09;DisposableBean Aware接口在生命周期实例化过…

企业定制AI智能名片商城小程序:重塑营销场景,引领数字化营销新纪元

在数字化时代的浪潮中&#xff0c;多企业AI智能名片商城小程序以其独特的魅力和创新的功能&#xff0c;为消费者带来了前所未有的购物体验。它不仅是一个汇聚各类商品的购物平台&#xff0c;更是一个充满活力和创造力的社群生态。通过强化社群互动、鼓励用户生成内容以及引入积…

深入浅出DBus-C++:Linux下的高效IPC通信

目录标题 1. DBus简介2. DBus-C的优势3. 安装DBus-C4. 使用DBus-C初始化和连接到DBus定义接口和方法发送和接收信号 5. dbus-cpp 0.9.0 的安装6. 创建一个 DBus 服务7. 客户端的实现8. 编译和运行你的应用9. 瑞芯微&#xff08;Rockchip&#xff09;的 Linux 系统通常会自带 db…

【iOS】pthread、NSThread

文章目录 前言一、pthread 使用方法pthread 其他相关方法 二、 NSThread创建、启动线程线程相关用法线程状态控制方法NSThread 线程安全和线程同步场景 线程的状态转换 前言 五一这两天准备将GCD相关的知识完&#xff0c;同时NSOperation与NSThread、pthread也是相关知识&…

matlab期末知识

1.期末考什么&#xff1f; 1.1 matlab操作界面 &#xff08;1&#xff09;matlab主界面 &#xff08;2&#xff09;命令行窗口 &#xff08;3&#xff09;当前文件夹窗口 &#xff08;4&#xff09;工作区窗口 &#xff08;5&#xff09;命令历史记录窗口 1.2 matlab搜索…

【网络】tcp协议如何保证可靠性

TCP&#xff08;Transmission Control Protocol&#xff09;是一种面向连接的、可靠的传输层协议&#xff0c;为网络通信提供了可靠性和连接稳定性。本文将详细介绍 TCP 协议如何保证数据的可靠传输和连接的稳定性&#xff0c;并分析其优缺点。 可靠性保证 序号和确认机制&…

3GPP官网下载协议步骤

1.打开官网 https://www.3gpp.org/ 2.点击 3.在界面选择要找的series&#xff0c;跳转到查找界面 以V2X通信协议为例&#xff0c;论文中通常会看到许多应用&#xff1a; [7] “Study on evaluation methodology of new Vehicle-to-Everything (V2X) use cases for LTE and NR…

普通二维码打开微信小程序并且传递参数

实现方法&#xff1a; 【1】确保有一个企业级别的认证过的微信小程序 【2】有一个https并且备案过的域名 【3】进入微信后台“开发”-“开发设置”-“扫普通链接二维码打开小程序”-“添加” 官方文档&#xff1a;https://developers.weixin.qq.com/miniprogram/introduction/q…