关于01背包的学习

什么是01背包问题?

有 N 件物品和一个最多能被重量为 W 的背包。第i件物品的重量是 weight[i],得到的价值是 value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

解题思路:

  • 确定 dp 数组及下标的含义,
  • 定义一个数组dp[ i ] [ j ]
  • i为当前物品的编号,j为当前背包能容纳的质量,dp[i][j] 表示背包容量为 j 时,能获得的最大价值。
  • 确定递推公式:
  • 根据第一步 dp 数组的定义可知,当我们遍历到第 i 个物品时,可以选择将第 i 个物品装入背包,也可以选择不装,这两种情况分别所对应的最大价值如下:
  • 当weight[ i ]<=j时装入:dp[ i ] [ j ] = dp[ i-1] [ j - weight[i]] + value[i] —— 如果装入第 i 个物品,则在装入之前需要背包先空出第 i 个物品的容量 weight[i],此时背包所获的的最大价值为 dp[ i ][j - weight[i]],然后再加上第 i 个物品的价值 value[i]
  • 当weight[ i ]>j时不装:dp[ i ][ j ] = dp[ i-1 ][ j ] —— 如果不装入第 i 个物品,就用除第 i 个物品之外的其它物品填满容量为 j 的背包,此时的最大价值就是 dp[ i-1 ][ j ]
  • 最终 dp[ i] [ j ] 取装入或者不装入第 i 个物品所获得的价值中最大的那个,即dp[ i ] [ j ] = max(dp[ i-1][ j ], dp[ i-1][j - weight[i]] + value[i])
  • dp[i][j] 递推公式:
    • 如果求背包能装的最大重量:dp[ i ][ j ] = Math.max(dp[ i-1][ j ], dp[ i-1][j - weight[i]] + value[i]);
    • 如果求装满容量为 j 的背包的方法数:dp[i][j] = dp[ i-1 ][ j ];
  • 初始化是严格按照dp 数组的定义来的,当 j 为0时,背包的容量为0,所能获取的最大价值 dp[i][0] 也是0
  • 然后开始从第一个物品开始遍历

什么题目能用01背包解决呢?

一堆东西(一组数),按照一定的方式进行组合、处理,能否凑成某种最值状态,或者凑成某种状态的方法数。能否拆分抽象成01背包的四要素:背包容量、物品编号、物品质量、物品价值。如果可以,这道题目可以使用01背包来解决。

例子:

力扣题目:分割等和子集

LeetCode链接: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

题目分析:

假设原数组内数字总和为 sum,若分成两个子集的元素和相等,则每个子集和为 sum / 2,即“是否能从非空数组 nums 中选出一些数,这些数的和能够达到sum / 2 “。那么我们可以发现这道题目符合01背包的概念。将这道题目抽象为01背包问题:背包的容量为sum / 2,物品就是数组的元素,物品编号是数组元素的下标、物品质量为数组元素的大小、物品价值也是数组元素的大小。

解题思路:

这道题要解决的是,数组中是否能选出几个元素加起来的值等于数组元素总和的一半。

  • 定义一个boolean[ i ] [ j ]数组来存储当前sum/2=j 时,能不能选出元素来凑成sum/2.如果能boolean[ i ] [ j ]的值为true,不能为false;i表示数组元素下标,j表示sum/2为j时。
  • 如果不选取任何正整数,则被选取的元素等于 0。因此对于所有 0≤i<n,都有 dp[i][0]=true。
  • 当 i==0时,只有一个正整数 nums[0] 可以被选取,因此 dp[0][nums[0]]=true。
  • 如果 j≥nums[i],则对于当前的数字 nums[i],可以选取也可以不选取,两种情况只要有一个为 true,就有 dp[i][j]=true

  • 如果不选取 nums[i],则 dp[i][j]=dp[i-1][j]

  • 如果选取 nums[i],则dp[i][j]=dp[i−1][j−nums[i]]

  • 如果 j<nums[i]j ,则在选取的数字的和等于 j 的情况下无法选取当前的数字 nums[i],因此有dp[i][j]=dp[i−1][j]。

  • 最终得到 dp[n-1] [total]即为答案

     
    class Solution {public boolean canPartition(int[] nums) {Arrays.sort(nums);   int n = nums.length;if(n<2){return false;}int sum=0;for(int i : nums ){sum+=i;}int total = sum/2;if(sum%2!=0){return false;}if(nums[n-1]>total){return false;}boolean [][] dp = new boolean[n][total+1];for(int i=1;i<n;i++){dp[i][0] = true;}dp[0][nums[0]] = true;for(int i=1;i<n;i++){int m = nums[i];for(int j=1;j<=total;j++){if(m<=j){dp[i][j] = dp[i-1][j] | dp[i-1][j-m];}else{dp[i][j] = dp[i-1][j];}}}return dp[n-1] [total];}
    }

 

力扣题目:最后一块石头的重量 II 

LeetCode链接:1049. 最后一块石头的重量 II

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

题目分析:

根据题目描述,当所有的石头都粉碎完时,石头的重量最小。因此可以将石头分为两堆,小的一堆、大的一堆。当小的一堆石头的重量无线接近甚至等于所有石头重量的一半的时候,剩余的石头重量最小。因此很明显,本题目符合01背包的特征。背包最大容量可以抽象为所有石头的一半质量,物品可以抽象为石头。

解题思路:

  • 定义一个维度为[n + 1][total + 1]的数组 dp[i][j] 表示当石头重量的一半为j的时候要被粉碎石头的重量,i表示为石头的编号,j表示石头重量的一半。
  • 当 i=0,没有任何石头,总重量一定是 0,对于任意 0≤j≤sum/2,dp[0][j]=0

  • 如果 j<stones[i−1],则不能选取当前石头,最大总重量为在前 i−1块石头中选取且总重量不超过 j 的情况下的最大总重量,因此最大总重量为 dp[i−1][j]

  • 如果 j≥stones[i−1],则可以不选取或选取当前石头,选择其中的最大总重量。
  • 如果不选取当前石头,则在前 i−1块石头中选取石头时总重量不超过 j,最大总重量为 dp[i−1][j]
  • 如果选取当前石头,则在前 i−1块石头中选取石头时总重量不超过 j−stones[i−1],前 i−1块石头的最大重量为 dp[i−1][j−stones[i−1]],当前石头的重量为 stones[i−1],最大总重量为 dp[i−1][j−stones[i−1]]+stones[i−1]。
  • 动态规划的状态转移方程如下:

    如果 j<stones[i−1],则 dp[i][j]=dp[i−1][j]

    如果 j≥stones[i−1],则 dp[i][j]=max⁡(dp[i−1][j],dp[i−1][j−stones[i−1]]+stones[i−1])

  • 2*dp[n][total]为粉碎石头的最大重量(粉碎石头时,两边的石头都要消耗的,所以乘2)

  • 最后sum - 2 * dp[n][total]则为最终答案

class Solution {public int lastStoneWeightII(int[] stones) {int n= stones.length;if(n<2){return stones[0];}int sum = 0;for (int stone : stones) {sum += stone;}int total = sum / 2;int[][] dp = new int[n + 1][total + 1];for (int i = 1; i <= n; i++) {for (int j = 0; j <= total; j++) {if (j < stones[i - 1]) {dp[i][j] = dp[i - 1][j];} else {dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i - 1]] + stones[i - 1]);}}}return sum - 2 * dp[n][total];}
}

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

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

相关文章

PostgreSQL Patroni_exporter 监控 patroni高可用工具

Patroni是Cybertec公司基于python语言开发的&#xff0c;可用于使用流复制来创建&#xff0c;管理&#xff0c;维护和监视高可用性PostgreSQL集群设置的工具。 目前&#xff0c;PatroniEtcd 是最为推荐的PostgreSQL数据库高可用方案之一。 PostgreSQL有postgres_exporter监控采…

ssl单向证书和双向证书校验测试及搭建流程

零、前提准备 说明&#xff1a; 50.50.1.118作为服务端&#xff0c;系统是 linux&#xff0c;openssl版本是&#xff1a;OpenSSL 1.1.1f 31 Mar 2020。 50.50.1.116是客户端&#xff0c;系统是Windows&#xff0c;openssl版本是&#xff1a;OpenSSL 3.0.5 5 Jul 2022 (Library…

BES 平台 SDK之LED的配置

本文章是基于BES2700 芯片&#xff0c;其他BESxxx 芯片可做参考&#xff0c;如有不当之处&#xff0c;欢迎评论区留言指出。仅供参考学习用&#xff01; BES 平台 SDK之代码架构讲解二_谢文浩的博客-CSDN博客 关于SDK 系统框架简介可参考上一篇文章。链接如上所示&#xff01…

583. 两个字符串的删除操作

思路 本题也是动态规划的解法&#xff0c;dp[i][j]代表的意思就是word1中0~i的字符串和word2中0 ~ j的字符串相等需要的步数&#xff0c;也是通过判断尾部字符是否相等的方式&#xff0c;如果相等的话也就不需要改动了取dp[i-1][j-1]的步数就行&#xff0c;如果不相等的话需要找…

react中问题记录

1. 使用history.goback()返回 页面没有重新调接口 解决方案&#xff1a;使用以下 API window.location.href document.referrer; 2.解析字符串html <div dangerouslySetInnerHTML{{ __html: content, }} />

CSS font-family 等宽字体

CSS font-family 等宽字体 font-family: "Lucida Console", Consolas, "Courier New", Courier, monospace; font-family: Courier New, Courier, Lucida Console, Consolas, monospace; font-family: Courier, Lucida Console, Consolas, Courier New,…

React 组件通信-全面解析

父子组件通信 // 导入 import { useState } from "react";import "./App.scss"; import { defaultTodos } from "./components/module/contentData";// 子组件 const Module ({ id, done, text, onToggle, onDelData }) > {return (<div…

JavaWeb(8)——前端综合案例2(节流和防抖)

目录 一、节流和防抖概念 二、实例演示 三、需要注意的 一、节流和防抖概念 二、实例演示 Lodash 简介 | Lodash中文文档 | Lodash中文网 (lodashjs.com) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><m…

【Redis】内存数据库Redis进阶(搭建各种集群)

目录 单机安装Redis搭建Redis主从集群搭建Redis哨兵集群 基于 CentOS 7 的 Redis 集群 单机安装Redis 安装 Redis 所需要的依赖&#xff1a; yum install -y gcc tcl将 Redis 安装包&#xff08;redis-6.2.4.tar.gz&#xff09;上传到任意目录 解压缩&#xff1a; tar -xzf …

Java NIO 详解

Java 从1.4开始引入NIO&#xff08;New IO&#xff09;&#xff0c;是一种基于块&#xff08;Block&#xff09;的IO机制&#xff0c;也称为非阻塞IO。相比于传统的Java IO&#xff08;IO流&#xff09;方式&#xff0c;Java NIO提供了更快速、高效、灵活的IO操作。 Java NIO的…

Aduino中eps环境搭建

这里只记录Arduino2.0以后版本&#xff1a;如果有外网环境&#xff0c;那么可以轻松搜到ESP32开发板环境并安装&#xff0c;如果没有&#xff0c;那就见下面操作&#xff1a; 进入首选项&#xff0c;将esp8266的国内镜像地址填入&#xff0c;然后保存&#xff0c;在开发板中查…

代码随想录算法训练营第二十九天 | Leetcode随机抽题检测

Leetcode随机抽题检测 160 相交链表未看解答自己编写的青春版重点题解的代码206 反转链表 一段用于复制的标题未看解答自己编写的青春版重点题解的代码日后再次复习重新写 234 回文链表未看解答自己编写的青春版重点综上&#xff0c;利用快慢指针找寻链表中间&#xff0c;就按加…

牛客网Verilog刷题——VL51

牛客网Verilog刷题——VL51 题目答案 题目 请编写一个十六进制计数器模块&#xff0c;计数器输出信号递增每次到达0&#xff0c;给出指示信号zero&#xff0c;当置位信号set 有效时&#xff0c;将当前输出置为输入的数值set_num。模块的接口信号图如下&#xff1a; 模块的时序图…

JVM基础篇-方法区与运行时常量池

JVM基础篇-方法区与运行时常量池 方法区 Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的方法区。方法区类似于传统语言的编译代码的存储区或者类似于操作系统进程中的“文本”段。它存储每个类的结构&#xff0c;例如运行时常量池、字段和方法数据&#xff0c;以及方法和…

Hadoop 集群如何升级?

前言 本文隶属于专栏《大数据技术体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据技术体系 正文 升级 Hadoop 集群需要细致的规划&#xff0c;特…

使用docker部署Wordpress

文章目录 1.创建网络2.创建volume存储3.拉取镜像4.创建mysql容器mysql修改密码 5.创建wordpress容器6.访问localhost:80就可以直接使用啦 1.创建网络 docker network create --subnet172.18.0.0/24 pro-net2.创建volume存储 # mysql 存储 docker volume create volume_mysql…

vscode 前端开发插件 2023

自己记录 安装vscode后必装插件 chinesegit 必装没啥可说 随时更新 1.CSS Navigation CTRL点击类名可跳转到对应样式位置。 如果是scss less的话。css peak插件无法生效 2.GitLens — Git supercharged 可以看到每一行的git提交记录。 3.Auto Rename Tag 可以同步更新…

笙默考试管理系统-MyExamTest(26)

笙默考试管理系统-MyExamTest&#xff08;26&#xff09; 目录 一、 笙默考试管理系统-MyExamTest 二、 笙默考试管理系统-MyExamTest 三、 笙默考试管理系统-MyExamTest 四、 笙默考试管理系统-MyExamTest 五、 笙默考试管理系统-MyExamTest 笙默考试管理系统-MyEx…

Elasticsearch入门用例

快速开始 使用版本&#xff1a;V7.12 资料来自官方文档 本指南幫助初學者學習如何&#xff1a; 將數據添加到 Elasticsearch 搜索和排序數據 在搜索過程中從非結構化內容中提取字段 测试运行&#xff1a; http://localhost:9200 响应&#xff1a; {"name": &qu…

CentOs 7利用iscaiadm工具发现并连接外接存储

CentOs 7利用iscaiadm工具发现并连接外接存储 1.1 使用iscsiadm发现存储 iscsiadm -m discovery -t st -p ${外接存储IP} # 执行结果may like ${外接存储IP}:3260,1 iqn.${存储唯一标识} 1.2 登入发现的存储 iscsiadm -m node -T iqn.${存储唯一标识} -p ${外接存储IP} -…