0/1背包问题总结

文章目录

  • 🍇什么是0/1背包问题?
  • 🍈例题
    • 🍉1.分割等和子集
    • 🍉2.目标和
    • 🍉3.最后一块石头的重量Ⅱ
  • 🍊总结

在这里插入图片描述
博客主页:lyyyyrics

🍇什么是0/1背包问题?

0/1背包问题是一个经典的组合优化问题,其描述如下:

假设有一个背包,它能够承载一定的重量。现在有一组物品,每个物品有各自的重量和价值。我们的目标是在不超过背包承载重量的前提下,选择一些物品放入背包中,使得背包中物品的总价值最大化。

具体来说,假设有 n n n个物品,其重量分别为 w 1 , w 2 , . . . , w n w_1, w_2, ..., w_n w1,w2,...,wn,对应的价值分别为 v 1 , v 2 , . . . , v n v_1, v_2, ..., v_n v1,v2,...,vn。背包的承载重量为 W W W。我们需要在这 n n n个物品中选择一些放入背包中,使得这些物品的总重量不超过 W W W,且总价值最大化。

数学公式可以表示为:

Maximize ∑ i = 1 n v i x i subject to ∑ i = 1 n w i x i ≤ W x i ∈ { 0 , 1 } , i = 1 , 2 , . . . , n \begin{align*} \text{Maximize} \quad & \sum_{i=1}^{n} v_ix_i \\ \text{subject to} \quad & \sum_{i=1}^{n} w_ix_i \leq W \\ & x_i \in \{0, 1\}, \quad i=1,2,...,n \end{align*} Maximizesubject toi=1nvixii=1nwixiWxi{0,1},i=1,2,...,n

其中, x i x_i xi表示第 i i i个物品是否放入背包中。若 x i = 1 x_i=1 xi=1,表示放入;若 x i = 0 x_i=0 xi=0,表示不放入。

🍈例题

🍉1.分割等和子集

题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

根据描述,这道题就是让我们求一个数组是否能将其分成两块 ,然后这两块是相等的,如果能返回true,如果不能则返回false。
算法原理:
首先我们注意到,这道题要将数组分成两个部分,这两个部分是否相等,我们可以转化为分成一个部分,这个部分是数组总和的一半?很显然是可以的,这样转换之后其实就已经是背包问题了,这个数组中的数就是物品,数组中的数就代表每个物品的价值,然后数组中的数的总和的一半就是这个背包的容量,问题就 转化为,我们是否可以从数组中挑出一些物品,使得物品的体积恰好能把这个 背包塞满?
状态表示:dp[i][j]表示前i个数中的所有的选法中,是否存在和为j的选法,如果存在则是true,如果不存在则就是false。
状态转移方程:状态转移方程还是考虑i位置和j位置。
在这里插入图片描述
如果能选的话,应该是选和不选中有一个满足就够了,所以这里应该还要取一个||,dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i]]
初始化:在这里插入图片描述
首先看第一行,从1开始,从0个数中选,和为1的,这种情况是不存在的,所以应该是false,后面的从0个数中选的都是false,,我们来看第一列,从0个数中选和为0,那就是不选,所以为true,从1个数中选和为0,可以不选,也是true,所以我们只需要 初始化第一列,初始化为true。
代码:

class Solution {
public:bool canPartition(vector<int>& nums){int n = nums.size();int sum = 0;//求和for (auto e : nums)sum += e;//如果和是奇数的话直接返回if (sum % 2 == 1)return false;//先定义一个aim表示和的一半int  aim = sum / 2;//创建dp表vector<vector<bool>> dp(n + 1, vector<bool>(aim + 1));//初始化dp表的第一列为true,因为如果和为零的话是有可能的。//如果什么都不选的话,当前和就是0for (int i = 0;i <= n;i++){dp[i][0] = true;}for (int i = 1;i <= n;i++){for (int j = 1;j <= aim;j++){//不选的话就是前一个状态的bool值dp[i][j] = dp[i - 1][j];//如果能选的话,只要有一种满足就表示满足if (j >= nums[i - 1])dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];}}//返回和为aim的状态return dp[n][aim];}
};

运行结果:
在这里插入图片描述

🍉2.目标和

题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题是给定一个数组,我们可以将数组中数 的符号我们可以随便改,最后串成一个加减法的式子,然后这个式子的值为target即可,这道题当然不是让我们返回true或者false,而是让我们返回方法的总数。
算法原理:
这道题其实我们可以将当中的数划分为两类:
在这里插入图片描述
我们将b规定为负数的绝对值。
所以最后可以得出:在这里插入图片描述
所以我们只需要看这个数组中是否组合能使得这个组合最后的和是a即可。
状态表示:dp[i][j]表示从前i个数中选,所有选法中和为j的方法。
状态转移方程:状态转移方程还是看第i个位置:
在这里插入图片描述
如果能选的话,则方法总数就是选和不选的和:dp[i][j]+=dp[i-1][j-nums[i]],但是有一个条件:j>nums[i]

代码:

class Solution 
{
public:int findTargetSumWays(vector<int>& nums, int target){int n = nums.size();int sum = 0;for (auto e : nums)sum += e;int aim = (sum + target) / 2;if (aim < 0 || (sum + target) % 2 == 1)return 0;vector<vector<int>> dp(n + 1, vector<int>(aim + 1));dp[0][0] = 1;for (int i = 1;i <= n;i++){for (int j = 0;j <= aim;j++){dp[i][j] = dp[i - 1][j];if (j >= nums[i - 1])dp[i][j] += dp[i - 1][j - nums[i - 1]];}}return dp[n][aim];}
};

运行结果:
在这里插入图片描述

🍉3.最后一块石头的重量Ⅱ

题目:

在这里插入图片描述
这道题的题目是“最后一块石头的重量 II”。

样例输出和输入:

在这里插入图片描述

给定一堆石头的重量数组stones,在每一回合中,选出两块石头粉碎,最后剩下的石头的重量可能为:

  1. 如果选出的两块石头重量相等,那么两块石头都会被完全粉碎;
  2. 如果选出的两块石头重量不相等,重量为较小的石头将会完全粉碎,而重量为较大的石头新重量为较大石头的重量减去较小石头的重量。

问题要求找到最后剩下的石头的最小可能重量。如果没有剩下的石头,返回0。给定一堆石头的重量数组stones,在每一回合中,选出两块石头粉碎,最后剩下的石头的重量可能为:

  1. 如果选出的两块石头重量相等,那么两块石头都会被完全粉碎;
  2. 如果选出的两块石头重量不相等,重量为较小的石头将会完全粉碎,而重量为较大的石头新重量为较大石头的重量减去较小石头的重量。

问题要求找到最后剩下的石头的最小可能重量。如果没有剩下的石头,返回0。

算法原理:

首先我们模拟一遍这个过程:
在这里插入图片描述

注意:上述过程是建立在前一个比后一个大的基础上模拟的
我们可以发现:当中的数也是有正有负,相当与也可以分成两个分类,一个正一个负:
在这里插入图片描述
在这里插入图片描述
其实我们不难看出,当a和b最接近的时候,这时候差值最小,所以这道题我们就可以转换成了0/1背包问题:
相当于a和b都接近于sum/2,所以这道题的背包容量是sum/2,
状态表示:dp[i][j]表示前i个物品中选,总和不超过j的,最大的和。
状态转移方程:在这里插入图片描述
当存在第一种情况的是否需要和不选的情况求一个最大值:dp[i][j]=max(dp[i-1][j],dp[i-1][j-stones[i]]+stones[i]
代码:

int lastStoneWeightII(vector<int>& stones)
{int n = stones.size();int sum = 0;for (auto e : stones)sum += e;vector<vector<int>> dp(n + 1, vector<int>(sum / 2 + 1));for (int i = 1;i <= n;i++){for (int j = 1;j <= sum / 2;j++){dp[i][j] = dp[i - 1][j];if (j >= stones[i - 1])dp[i][j] = max(dp[i - 1][j - stones[i - 1]] + stones[i - 1], dp[i - 1][j]);}}int a = dp[n][sum / 2];int b = sum - a;return abs(a - b);
}

空间优化过的代码:二维---->一维

class Solution {
public:int lastStoneWeightII(vector<int>& stones){int n = stones.size();int sum = 0;for (auto e : stones)sum += e;vector<int> dp(sum / 2 + 1);for (int i = 1;i <= n;i++)for (int j = sum / 2;j >= stones[i - 1];j--)dp[j] = max(dp[j - stones[i - 1]] + stones[i - 1], dp[j]);int a = dp[sum / 2];int b = sum - a;return abs(a - b);}
};

运行结果:

在这里插入图片描述

🍊总结

0/1 背包问题是组合优化中的经典问题,通过研究和解决这一问题,可以深入理解动态规划的基本思想和应用。本文详细介绍了0/1背包问题的定义、数学模型及其动态规划解法,并通过C++代码示例展示了具体的实现步骤。

通过本次总结,希望读者能够掌握如何将理论知识应用于实际问题,理解状态转移方程的推导过程,以及如何优化算法以提升效率。背包问题不仅在学术研究中具有重要意义,还广泛应用于资源分配、项目管理等实际领域。掌握这一问题的解决方法,可以为解决更复杂的优化问题打下坚实的基础。

在今后的学习中,建议读者多多练习不同变种的背包问题,如完全背包、多重背包问题等,以进一步提升自己的算法设计和分析能力。感谢阅读,希望本文对你的学习和应用有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/41155.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CFS三层内网渗透——第二层内网打点并拿下第三层内网(三)

目录 八哥cms的后台历史漏洞 配置socks代理 ​以我的kali为例,手动添加 socks配置好了&#xff0c;直接sqlmap跑 ​登录进后台 蚁剑配置socks代理 ​ 测试连接 ​编辑 成功上线 上传正向后门 生成正向后门 上传后门 ​内网信息收集 ​进入目标二内网机器&#xf…

小程序分包加载、独立分包、分包预加载等

一、小程序分包加载 小程序的代码通常是由许多页面、组件以及资源等组成&#xff0c;随着小程序功能的增加&#xff0c;代码量也会逐渐增加&#xff0c; 体积过大就会导致用户打开速度变慢&#xff0c;影响用户的使用体验。分包加载是一种小程序优化技术。将小程序不同功能的代…

如果在已经打开的网页里面,我点击了一个链接,这个链接在新的标签页打开,如何能得到新的标签页其返回的数据收发数据。

要在已打开的网页中点击一个链接并在新标签页中打开&#xff0c;然后捕获新标签页中的所有HTTP请求和响应&#xff0c;你可以使用Selenium库结合selenium-wire插件。下面是一个示例代码&#xff0c;展示了如何实现这一功能&#xff1a; python import json from selenium imp…

【微信小程序开发实战项目】——花店微信小程序实战项目(4)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

Nginx的安装与配置 —— Linux系统

一、Nginx 简介 1.1 什么是 Nginx Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务…

Linux系统部署MongoDB开源文档型数据库并实现无公网IP远程访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 &#x1f4a1; 推荐 前些天发现了一个巨牛的人工智能学习网站&am…

现代农业利器:土壤检测仪器的应用与未来

在现代农业发展的浪潮中&#xff0c;土壤检测仪器以其精准、高效的特点&#xff0c;成为了农业生产的得力助手。这些看似不起眼的设备&#xff0c;实际上在保障农产品质量、提高农业生产效率方面发挥着举足轻重的作用。 一、土壤检测仪器&#xff1a;现代农业的“眼睛” 土壤检…

Vector的扩容过程是怎样的

Vector的扩容过程在C中是一个动态调整内存空间以容纳更多元素的过程。这一过程主要发生在向Vector中添加元素时&#xff0c;如果当前Vector的容量不足以容纳新元素&#xff0c;就会触发扩容操作。以下是Vector扩容过程的详细步骤&#xff1a; 扩容机制 判断是否需要扩容&…

记录第一次写脚本

使用csh语言&#xff0c;Linux系统操作的 写和执行csh&#xff08;C Shell&#xff09;脚本不需要额外的软件&#xff0c;只需要一个支持csh的终端环境。 1.检查是否安装了C Shell 在终端terminal运行以下命令 which csh 如果返回路径&#xff0c;比如/bin/csh&#xff0c…

SpringBoot 启动流程六

SpringBoot启动流程六 这句话是创建一个上下文对象 就是最终返回的那个上下文 我们这个creatApplicationContext方法 是调用的这个方法 传入一个类型 我们通过打断点的方式 就可以看到context里面的东西 加载容器对象 当我们把依赖改成starter-web时 这个容器对象会进行…

STM32-HAL-FATFS(文件系统)(没做完,stm32f103zet6(有大佬的可以在评论区说一下次板子为什么挂载失败了))

1STM32Cube配置 1-1配置时钟 1-2配置调试端口 1-3配置uart 1-4配置SDIO&#xff08;注意参数&#xff09;&#xff08;其中他的初始化的异常函数给注释&#xff0c;SD卡文件写了&#xff09; 配置了还要打开中断和DMA可在我的其他文章中看一样的 1-5配置FatFs (只改了图选中…

java中响应式编程:@FunctionalInterface用法实例

在Java中&#xff0c;Function<T, R>接口是Java 8引入的函数式接口之一&#xff0c;主要用来代表一个输入参数并产生一个结果的函数。它是响应式编程和函数式编程风格的重要组成部分&#xff0c;特别是在处理流&#xff08;Stream&#xff09;和异步操作时非常有用。 Fu…

QT c++函数模板与类模板的使用

QT c类模板的使用 #pragma once#include <QtWidgets/QMainWindow> #include "ui_QtWidgetsApplication5.h"class QtWidgetsApplication5 : public QMainWindow {Q_OBJECTpublic:QtWidgetsApplication5(QWidget *parent nullptr);~QtWidgetsApplication5();te…

Arthas实战(4)- 线程死锁问题排查

一、 准备测试应用 新建一个 SpringBoot应用&#xff0c;写一段线程死锁的代码&#xff1a; GetMapping("/threadLock") public void threadLock() {Thread thread1 new Thread(() -> {synchronized (resource1) {System.out.println(Thread.currentThread().g…

Solution

(解决方案)可行性研究报告暨设计方案-zengwenfeng.doc 基本上都要300-500多页&#xff0c;大型【纯软件】&#xff0c;县级0-200万&#xff0c;市级项目500-1500万不等&#xff0c;省部级1000-10000万不等都有。本例为过往已完成项目案例目录结构。搞方案都要准备1-3个月呢。所…

go语言 类型和常量

go语言 类型和常量 一、基础类型 Go语言是一种静态类型语言&#xff0c;这意味着所有变量的类型在编译时必须明确&#xff0c;并且一旦定义&#xff0c;类型就不能改变。 1.数字类型 整数类型 int8&#xff1a;占1个字节&#xff0c;范围是-128到127。int16&#xff1a;占2…

房屋租赁管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;中介管理&#xff0c;房屋信息管理&#xff0c;房屋类型管理&#xff0c;租房订单管理&#xff0c;租房信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;房屋信息&a…

极狐GitLab 将亮相2024空天信息大会暨数字地球生态峰会,携手中科星图赋能空天行业开发者

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

测试类型介绍-功能测试入门指南

1. 功能测试定义​ 功能测试&#xff0c;作为软件质量保证的关键环节&#xff0c;专注于验证软件是否按预期执行其指定功能。它直接面向用户需求&#xff0c;确保每一个功能点都能正确无误地工作。简而言之&#xff0c;功能测试是检查软件功能是否符合设计规范的过程。 2. 为…

Django文档简化版——Django快速入门——创建一个基本的投票应用程序

Django快速入门——创建一个基本的投票应用程序 准备工作1、创建虚拟环境2、安装django 1、请求和响应&#xff08;1&#xff09;创建项目&#xff08;2&#xff09;用于开发的简易服务器&#xff08;3&#xff09;创建投票应用&#xff08;4&#xff09;编写第一个视图1、编写…