【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题

在这里插入图片描述

本篇博客给大家带来的是01背包问题之动态规划解法技巧.
🐎文章专栏: 动态规划
🚀若有问题 评论区见
欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .

王子,公主请阅🚀

  • 要开心
    • 要快乐
      • 顺便进步
  • 1. 01背包
  • 2. 分割等和子集

要开心

要快乐

顺便进步

1. 01背包

题目链接: DP41 【模板】01背包

题目内容:
描述
在这里插入图片描述

示例1
输入:
3 5
2 10
4 5
1 4

输出:
14
9

说明:
装第一个和第三个物品时总价值最大,但是装第二个和第三个物品可以使得背包恰好装满且总价值最大。
示例2
输入:
3 8
12 6
11 8
6 8

输出:
8
0

说明:
装第三个物品时总价值最大但是不满,装满背包无解。
备注:
要求O(nV)的时间复杂度,O(V)空间复杂度

第一Ⅰ问的动态规划

1. 状态表示
在这里插入图片描述

01背包问题本质上还是 线性dp问题,按线性dp来定义状态即可.
第Ⅰ问: 尝试一维定义
dp[i] 表示在前 i 个位置中选择物品, 在所有的选法中, 物品总体积不超过背包容量V 时的最大价值.
上述一维定义在写状态转移方程时不能保证所选物品体积不会超过背包的容量,并且选完之后背包剩余容量也时未知的.一维定义解决不了问题,
用二维定义dp[i][j] 表示在前 i 个位置中选择物品, 物品总体积不超过 V的所有选法中能选出来的最大价值.

2. 状态转移方程
根据最后一个位置是否选择, 来划分问题:
① i 物品不选, dp[i] = dp[i-1][j]
② i 物品要选, 需要保证剩余容量大于等于0, j-v[i]>= 0, w[i] + dp[i-1][j-v[i]];

3. 初始化
选择物品是从下标1 开始的, 到n结束, 那么dp表就需要多创建一行一列,处理两个细节问题:
①下标之间的对应关系: i -> i j -> j
②初始化虚拟节点:
第一行表示的是 物品可选,总体积不超过 j 的最大价值. 既然没有物品,那就不选,全都为0.
第一列表示的是 所选物品总体积不超过0的最大价值. 此时最大价值就是0,不选即可,全都为0.

在这里插入图片描述

4. 填表顺序
根据状态转移方程可知,要想得到dp[i][j] 就得先知道dp[i-1][j]或者dp[i-1][j-v[i]],
所以应该从上往下填写每一行
从左往右填写每一列.

5. 返回值
打印 dp[n][V]即可.

第二 Ⅱ问的动态规划

1. 状态表示
在这里插入图片描述

与第Ⅰ问同样的分析方法:
二维定义dp[i][j] 表示在前 i 个位置中选择物品, 物品总体积刚好为 V的所有选法中能选出来的最大价值.
可能存在所有选法都不能恰好装满背包,我们规定此时dp[i][j] = -1;

2. 状态转移方程
根据最后一个位置是否选择, 来划分问题:
① i 物品不选, dp[i] = dp[i-1][j]
② i 物品要选, 需要保证剩余容量大于等于0, j-v[i]>= 0, w[i] + dp[i-1][j-v[i]];

3. 初始化
选择物品是从下标1 开始的, 到n结束, 那么dp表就需要多创建一行一列,处理两个细节问题:
①下标之间的对应关系: i -> i j -> j
②初始化虚拟节点:
第一行表示的是 没有物品可选,总体积等于 j 的最大价值.dp[0][0] = 0, 后面 无论选不选,总价值都达不到 j ,于是全都初始化为-1.
第一列表示的是 所选物品总体积等于0的最大价值. 此时最大价值就是0,不选即可,全都为0.

在这里插入图片描述

4. 填表顺序
根据状态转移方程可知,要想得到dp[i][j] 就得先知道dp[i-1][j]或者dp[i-1][j-v[i]],
所以应该从上往下填写每一行
从左往右填写每一列.

5. 返回值
打印 dp[n][V]即可.

第三 优化

①利用滚动数组做空间上的优化
在这里插入图片描述

在这里插入图片描述
②直接在原始代码上修改
Ⅰ删除所有的 i 维
(★)Ⅱ 填表时从右往左遍历 j .

第四 代码实现

// //优化前://  Scanner in = new Scanner(System.in);// int N = 1010;// // 注意 hasNext 和 hasNextLine 的区别// int n = in.nextInt();// int V = in.nextInt();// int[][] dp1 = new int[N][N];// int[][] dp2 = new int[N][N];// int[] v = new int[N];// int[] w = new int[N];// for (int i = 1; i <= n; ++i) {//     v[i] = in.nextInt();//     w[i] = in.nextInt();// }// //1.解决第一个问题(1)求这个背包至多能装多大价值的物品?// //填表// for (int i = 1; i <= n; ++i) {//     for (int j = 0; j <= V; ++j) { //修改遍历顺序//      dp1[i][j] = dp1[i-1][j];//      if(j >= v[i]) {//         dp1[i][j] = Math.max(dp1[i][j], w[i] + dp1[i-1][j - v[i]]);//      }//     }// }// System.out.println(dp1[n][V]);// //2. 解决第二个问题 (2)若背包恰好装满,求至多能装多大价值的物品?// for (int i = 1; i <= V; ++i) {//     dp2[0][i] = -1;// }// for (int i = 1; i <= n; ++i) {//     for (int j = 0; j <= V; ++j) {//         dp2[i][j] = dp2[i-1][j];//         if (j-v[i] >= 0 && dp2[i-1][j - v[i]] != -1) {//             dp2[i][j] = Math.max(dp2[i][j], w[i] + dp2[i-1][j - v[i]]);//         }//     }// }// //若是-1则输出0, 若不是则正常输出.// System.out.println((dp2[n][V] == -1 ? 0 : dp2[n][V]));//优化后:Scanner in = new Scanner(System.in);int N = 1010;// 注意 hasNext 和 hasNextLine 的区别int n = in.nextInt();int V = in.nextInt();int[] dp1 = new int[N];int[] dp2 = new int[N];int[] v = new int[N];int[] w = new int[N];for (int i = 1; i <= n; ++i) {v[i] = in.nextInt();w[i] = in.nextInt();}//1.解决第一个问题(1)求这个背包至多能装多大价值的物品?//填表for (int i = 1; i <= n; ++i) {for (int j = V; j >= v[i]; --j) { //修改遍历顺序dp1[j] = Math.max(dp1[j], w[i] + dp1[j - v[i]]);}}System.out.println(dp1[V]);//2. 解决第二个问题 (2)若背包恰好装满,求至多能装多大价值的物品?for (int i = 1; i <= V; ++i) {dp2[i] = -1;}for (int i = 1; i <= n; ++i) {for (int j = V; j >= v[i]; --j) {if (dp2[j - v[i]] != -1) {dp2[j] = Math.max(dp2[j], w[i] + dp2[j - v[i]]);}}}//若是-1则输出0, 若不是则正常输出.System.out.println((dp2[V] == -1 ? 0 : dp2[V]));

2. 分割等和子集

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

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

示例 1:

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

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

提示:

1 <= nums.length <= 200
1 <= nums[i] <= 100

第一 预处理

直接去判断两个子集的元素和是否相等会有点复杂, 可以转化为只研究一个子集等于原数组元素和的一半, 即在数组中选择一些数, 这些数的和是否等于原数组元素和的一半.

第二 动态规划

1. 状态表示
根据第一题模板题可知定义状态的方式:
dp[i][j]表示在nums的前 i 个位置中选择一些数,所有选法中,是否存在一些数,使得这些数之和为 j.

2. 状态转移方程
根据最后一个位置nums[i]是否选择来划分情况:
①nums[i]不选: dp[i][j] = dp[i-1][j];
②nums[i]要选: 需要保证所选数之和不超过 j . j - nums[i] >= 0, dp[i][j-nums[i]];

3. 初始化
dp表多创建一行一列,需要处理两个问题:
①dp表与nums表元素之间的对应关系:
i -> i-1; j -> j-1
②初始化虚拟节点(就是多创建的一行一列),保证填表的正确性:

第一行 i=0意味着没有元素可选,怎么选最大值都只能是0,所以dp[0][0] = true,其余全部初始化为false.
第一列 j=0意味着需要凑成和为0, 直接不选即可. 故从i=1开始全部初始化为true.

在这里插入图片描述

4. 填表顺序
根据状态转移方程可知,要想求得dp[i][j]就得先知道dp[i-1][j]和dp[i-1][j-nums[i]],所以可知填表顺序为:
从上往下填写每一行
每一行从左往右填写

5. 返回值
返回dp[nums.length][原数组元素和的一半]

第三 优化

①利用滚动数组做空间上的优化
在这里插入图片描述

在这里插入图片描述
②直接在原始代码上修改
Ⅰ删除所有的 i 维
(★)Ⅱ 填表时从右往左遍历 j .

第四 代码实现

class Solution {public boolean canPartition(int[] nums) {//     int n = nums.length;//     int sum = 0;//     for(int x : nums) sum += x;//     if(sum%2 == 1) return false;//     int aim = sum/2;//     boolean[][] dp = new boolean[n+1][aim+1];//     for(int i = 0;i <= n;++i) {//         dp[i][0] = true;//     }//     for(int i = 1;i <= n;++i) {//         if(i < n) {//             sum += nums[i];//         }//         for(int j = 1;j <= aim;++j) {//             dp[i][j] = dp[i-1][j];//             if(j >= nums[i-1] && dp[i][j] == false) {//                 dp[i][j] = dp[i-1][j-nums[i-1]];//             }//         }//     }//     return dp[n][aim];// }//优化: 删除第一维, 从右往左遍历第二维int n = nums.length;int sum = 0;for(int x : nums) sum += x;if(sum%2 == 1) return false;int aim = sum/2;boolean[] dp = new boolean[aim+1];dp[0] = true;for(int i = 1;i <= n;++i) {if(i < n) {sum += nums[i];}for(int j = aim;j >= nums[i-1];--j) { //修改遍历顺序,本质上是滚动数组的优化.if(dp[j] == false) {dp[j] = dp[j-nums[i-1]];}}}return dp[aim];}
}

本篇博客到这里就结束啦, 感谢观看 ❤❤❤

🐎期待与你的下一次相遇😊😊😊

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

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

相关文章

yolov11 pose 推理代码

目录 效果图: yolo_pose.py 效果图: yolo_pose.py import osimport cv2 from PIL import Imagefrom ultralytics import YOLO import json from pathlib import Path import tqdmclass YOLOPose:def __init__(self, detections_file):self.detections_file = detections_f…

MFC程序设计(二)基于对话框编程

从现在开始&#xff0c;我们将以基于对话框的MFC应用程序来讲解MFC应用 向导生成基于对话框MFC应用程序 对话框是一种特殊类型的窗口&#xff0c;绝大多数Windows程序都通过对话框与用户进行交互。在Visual C中&#xff0c;对话框既可以单独组成一个简单的应用程序&#xff0…

ubuntu20.04有亮度调节条但是调节时亮度不变

尝试了修改grub文件&#xff0c;没有作用&#xff0c;下载了brightness-controllor&#xff0c;问题解决了。 sudo add-apt-repository ppa:apandada1/brightness-controller sudo apt update sudo apt install brightness-controller 之后在应用软件中找到brightness-contro…

深入探讨视图更新:提升数据库灵活性的关键技术

title: 深入探讨视图更新:提升数据库灵活性的关键技术 date: 2025/1/21 updated: 2025/1/21 author: cmdragon excerpt: 在现代数据库的管理中,视图作为一种高级的抽象机制,为数据的管理提供了多种便利。它不仅简化了复杂查询的过程,还能用来增强数据的安全性,限制用户…

75,【7】BUUCTF WEB [Weblogic]SSRF(未作出)

看到这个更是降龙十八掌 给的源代码进不去 给的靶场打不开 未完待续

16_动态提示窗口_协程延时

创建动态提示窗口DynamicWnd.cs 编写代码 using UnityEngine; using UnityEngine.UI; //功能 : 动态窗口界面 public class DynamicWnd : WindowsRoot{public Animation tipsAni;public Text txtTips;protected override void InitWnd() {base.InitWnd();//在启动时先隐藏提示…

麒麟监控工具rpm下载

确认系统 cat /etc/.productinfo麒麟v10 sp1 sp2 sp3 rpm包下载链接 sar - sysstat mtr iostat - sysstat netstat - net-tools https://update.cs2c.com.cn/NS/V10/V10SP3-2403/os/adv/lic/base/x86_64/Packages/sysstat-12.2.1-7.p01.ky10.x86_64.rpm https://update.cs…

2024年智慧消防一体化安全管控年度回顾与2025年预测

随着科技的飞速发展&#xff0c;智慧营区一体化安全管控在2024年取得了显著进展&#xff0c;同时也为2025年的发展奠定了坚实基础。 2024年年度回顾 政策支持力度持续加大&#xff1a;国家对消防安全的重视程度不断提高&#xff0c;出台了一系列涵盖技术创新、市场应用、人才培…

C#深度神经网络(TensorFlow.NET)

C#深度神经网络 文章目录 C#深度神经网络前言专业术语讲解模型[Model]向量[Vector]矩阵[Matrix]张量[Tensor]批量大小&#xff08;Batch Size&#xff09;迭代次数&#xff08;Epochs&#xff09;交叉熵[Cross Entropy] 训练流程数据预处理数据打标签数据转换标准化/归一化选择…

java 根据前端传回的png图片数组,后端加水印加密码生成pdf,返回给前端

前端传回的png图片数组&#xff0c;后端加水印加密码生成pdf&#xff0c;返回给前端 场景&#xff1a;重点&#xff1a;maven依赖controllerservice 场景&#xff1a; 当前需求&#xff0c;前端通过html2canvas将页面报表生成图片下载&#xff0c;可以仍然不满意。 需要java后…

Linux(LAMP)

赛题拓扑&#xff1a; 题目&#xff1a; 安装WEB服务。 服务以用户webuser系统用户运行。 限制WEB服务只能使用系统500M物理内存。 全站点启用TLS访问&#xff0c;使用本机上的“CSK Global Root CA”颁发机构颁发&#xff0c;网站证书信息如下&#xff1a; C CN ST China…

vue3+elementPlus之后台管理系统(从0到1)(day3-管理员管理)

管理员管理 搭建管理员页面 在views中创建一个manager文件夹&#xff0c;并创建ManagerIndexView.vue、MangagerListView.vue、UserList.vue <!-- src/views/manager/ManagerIndexView.vue --> <template><!-- 作为一个占位符&#xff0c;用于渲染与当前 URL…

CSRF漏洞学习总结

一、什么是CSRF漏洞&#xff1f; CSRF&#xff08;Cross-Site Request Forgery&#xff0c;跨站请求伪造&#xff09;是一种网络攻击&#xff0c;它利用受害者在受信任网站上的已认证会话&#xff0c;来执行非预期的行动。这种攻击的核心在于&#xff0c;攻击者能够诱使受害者…

前端Vue2项目使用md编辑器

项目中有一个需求&#xff0c;要在前端给用户展示内容&#xff0c;内容有 AI 生成的&#xff0c;返回来的是 md 格式&#xff0c;所以需要给用户展示 md 格式&#xff0c;并且管理端也可以编辑这个 md 格式的文档。 使用组件库 v-md-editor。 https://code-farmer-i.github.i…

【JDBC】数据库连接的艺术:深入解析数据库连接池、Apache-DBUtils与BasicDAO

文章目录 前言&#x1f30d; 一.连接池❄️1. 传统获取Conntion问题分析❄️2. 数据库连接池❄️3.连接池之C3P0技术&#x1f341;3.1关键特性&#x1f341;3.2配置选项&#x1f341;3.3使用示例 ❄️4. 连接池之Druid技术&#x1f341; 4.1主要特性&#x1f341; 4.2 配置选项…

Codeforces Round 1000 (Div. 2)(前三题)

A. Minimal Coprime 翻译&#xff1a; 如果 l 和 r 互为同素数&#xff0c;则正整数 [l,r] 的一段称为同素段。 如果一个共素数段 [l,r] 不包含任何不等于它本身的共素数段&#xff0c;那么这个共素数段 [l,r] 就叫做最小共素数段。为了更好地理解这句话&#xff0c;可以参考注…

数据库事务详解

事务-1-数据库事务 今天聊一聊数据库的事务&#xff0c;这里以MySQL为例子。 在MySQL中&#xff0c;事务&#xff08;Transaction&#xff09;是一组SQL操作的集合&#xff0c;这些操作要么全部成功执行&#xff0c;要么全部失败回滚&#xff0c;确保数据的一致性和完整性。事…

攻防世界GFSJ1012 pwnstack

题目编号&#xff1a;GFSJ1012 附件下载后是一个c和库文件&#xff1a; 获取在线场景是 1. 获取伪代码 Exeinfo打开pwn2&#xff0c;分析如图&#xff0c;64位。 IDA Pro(64-bit)打开pwn2&#xff0c;生成伪代码 2. 分析代码漏洞 /* This file was generated by the Hex-Rays …

最小距离和与带权最小距离和

1. 等权中位数 背景&#xff1a; 给定一系列整数&#xff0c;求一个整数x使得x在数轴上与所有整数在数轴上的距离和最小。 结论&#xff1a; 这一系列的整数按顺序排好后的中位数(偶数个整数的中位数取 n 2 或 n 2 1 \frac{n}{2}或\frac{n}{2}1 2n​或2n​1都可)一定是所求点…

【LeetCode 刷题】栈与队列-队列的应用

此博客为《代码随想录》栈与队列章节的学习笔记&#xff0c;主要内容为队列的应用相关的题目解析。 文章目录 239. 滑动窗口最大值347. 前 K 个高频元素 239. 滑动窗口最大值 题目链接 class Solution:def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]…