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

系列文章目录


目录

  • 系列文章目录
  • 动态规划:01背包理论基础
    • ①二维数组
    • ②一维数组(滚动数组)
  • 416. 分割等和子集
    • ①回溯法(超时)
    • ②动态规划(01背包)
      • 未剪枝版
      • 剪枝版


动态规划:01背包理论基础

(1)输入读取方法:

  1. Scanner sc = new Scanner(System.in);String str = sc.nextLine();int m = Integer.parseInt(str.split(" ")[0]);int n = Integer.parseInt(str.split(" ")[1]);//将String[]数组通过stream流转换成int[]数组int[] weights = Arrays.stream(sc.nextLine().split(" ")).mapToInt(/*s->Integer.parseInt(s)*/Integer::parseInt).toArray();int[] values =Arrays.stream(sc.nextLine().split(" ")).mapToInt(new ToIntFunction<String>() {@Overridepublic int applyAsInt(String value) {return Integer.parseInt(value);}}).toArray();
    
  2. Scanner sc = new Scanner(System.in);// 读取背包容量和物品数量int m = sc.nextInt();int n = sc.nextInt();sc.nextLine(); // 消耗掉输入缓冲区的换行符// 读取物品重量和价值int[] weights = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();int[] values = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
    
  3. // 获取输入数据Scanner sc = new Scanner(System.in);int m = sc.nextInt();int n = sc.nextInt();int[] weights = new int[m];for (int i = 0; i < m; i++){weights[i] = sc.nextInt();}int[] values = new int[m];for (int i = 0; i < m; i++){values[i] = sc.nextInt();}
    

①二维数组

(1)确定dp数组及其含义:
表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
(2)确定递推关系

  • 容量不够:一定放不下,直接返回不放 i 的最大价值。
  • 容量够:根据两种方案的价值做选择,选价值大的。
    • 不放i:相当于在 0 ~ (i-1) 件物品中选择,容量不变;
    • i:在确定放 i 的前提下(腾出空间给 i ),获取背包能产生的最大价值,再加上 i 的价值。

(3)考虑初始化
初始化第一行:对应物品0,如果背包容量不够,则设置为0,如果够,则设置为values[0]
初始化第一列:对应背包容量0,则无论是什么物品都放不下,不能产生任何价值,直接为默认值0即可。

代码如下:

import java.util.Arrays;
import java.util.Scanner;
import java.util.function.ToIntFunction;public class BagProblem {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String str = sc.nextLine();int m = Integer.parseInt(str.split(" ")[0]);int n = Integer.parseInt(str.split(" ")[1]);//将String[]数组通过stream流转换成int[]数组int[] weights = Arrays.stream(sc.nextLine().split(" ")).mapToInt(/*s->Integer.parseInt(s)*/Integer::parseInt).toArray();int[] values =Arrays.stream(sc.nextLine().split(" ")).mapToInt(new ToIntFunction<String>() {@Overridepublic int applyAsInt(String value) {return Integer.parseInt(value);}}).toArray();//确定dp数组下标及含义:dp[i][j] 表示从下标为0-i的物品里任取,放到容量为j的背包中,价值总和最大为多少int[][] dp = new int[m][n+1];//需要考虑容量和物品数量为0的情况//dp数组初始化for (int i = 0; i < m; i++) {//列初始化dp[i][0] = 0;}for (int j = weights[0]; j <= n; j++) {//行初始化dp[0][j] = values[0];}//确定遍历顺序(先遍历物品再遍历容量或者先遍历容量再遍历背包都行)//①先遍历物品再遍历容量for (int i = 1; i < m; i++) {for (int j = 1; j <= n; j++) {/*** 当前背包的容量都没有当前物品i大的时候,是不放物品i的* 那么前i-1个物品能放下的最大价值就是当前情况的最大价值*/if(j<weights[i]){dp[i][j] = dp[i - 1][j];}else {/*** 当前背包的容量可以放下物品i* 那么此时分两种情况:*    1、不放物品i*    2、放物品i* 比较这两种情况下,哪种背包中物品的最大价值最大*/dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i]] + values[i]);}}}System.out.println(dp[m-1][n]);}
}

②一维数组(滚动数组)

(1)确定dp数组及其含义:
在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]
(2)确定递推关系

  • 容量不够: dp[j] ,不放物品i
  • 容量够:根据两种方案的价值做选择,选价值大的。
    • 不放idp[j] ,相当于在 0 ~ (i-1) 件物品中选择,容量不变;
    • idp[j - weight[i]] + value[i],在确定放 i 的前提下(腾出空间给 i ),获取背包能产生的最大价值,再加上 i 的价值。

(3)考虑初始化
dp[0]=0,因为背包容量为0所背的物品的最大价值就是0。那么dp数组除了下标0的位置,初始为0,其他下标应该初始化多少呢?看一下递归公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); dp数组在推导的时候一定是取价值最大的数,如果题目给的价值都是正整数那么非0下标都初始化为0就可以了。

import java.util.Arrays;
import java.util.Scanner;
public class BagProblem {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int m = sc.nextInt();int n = sc.nextInt();sc.nextLine();//接收换行符int[] weights = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();int[] values = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();//确定dp数组及含义(背包容量为j的背包所能装的最大价值int[] dp = new int[n + 1];//dp数组初始化dp[0] = 0;//当背包容量为0时,最大价值也为0for (int i = 0; i < m; i++) {//遍历物品for (int j = n; j >= 0; j--) {//遍历容量(倒序遍历)if (j < weights[i]) {dp[j] = dp[j];} else {dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);}}}System.out.println(dp[n]);}
}

416. 分割等和子集

①回溯法(超时)

import java.util.Arrays;public class SplitEqualSumSubsets {public static void main(String[] args) {int[] nums = {3,3,3,4,5};Solution solution = new Solution();boolean answer = solution.canPartition(nums);System.out.println(answer);}
}class Solution {int sum = 0;int tempSum = 0;public boolean canPartition(int[] nums) {for (int i = 0; i < nums.length; i++) {sum += nums[i];}if (sum % 2 != 0) return false;//如果总和为奇数,则无法分割为两个等和子集//对数组从小到大排序Arrays.sort(nums);return backTracking(nums, 0);}public boolean backTracking(int[] nums, int startIndex) {//确定回溯函数的参数及返回值//确定回溯函数终止条件if (tempSum == sum / 2) return true;if (tempSum > sum / 2) {return false;}//确定单层递归逻辑boolean answer1 = false;for (int i = startIndex; i < nums.length; i++) {tempSum += nums[i];answer1 = backTracking(nums, i + 1);if(answer1)return true;// 如果找到一个可行解,立即返回,不再往下遍历tempSum -= nums[i];//回溯}return answer1;}
}

②动态规划(01背包)

未剪枝版

class Solution {public boolean canPartition(int[] nums) {int sum = 0;for (int i = 0; i < nums.length; i++) {sum += nums[i];}//总和为奇数,不能平分if (sum % 2 != 0) return false;//确定dp数组含义(容量为j的背包,放进0~i任意物品后,背的最大重量。int target = sum / 2;int[] dp = new int[target + 1];//dp数组初始化dp[0] = 0;for (int i = 0; i < nums.length; i++) {//先遍历物品for (int j = target; j >= 0; j--) {//倒序遍历背包容量if (j < nums[i]) {dp[j] = dp[j];} else {dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);}//System.out.print(dp[j]);}//System.out.println();}return dp[target] == target;//如果背包装满了,即能找到等和子集}
}

剪枝版

class Solution {public boolean canPartition(int[] nums) {int sum = 0;for (int i = 0; i < nums.length; i++) {sum += nums[i];}//总和为奇数,不能平分if (sum % 2 != 0) return false;//确定dp数组含义(容量为j的背包,放进0~i任意物品后,背的最大重量。int target = sum / 2;int[] dp = new int[target + 1];//dp数组初始化dp[0] = 0;for (int i = 0; i < nums.length; i++) {//先遍历物品for (int j = target; j >= 0; j--) {//倒序遍历背包容量if (j < nums[i]) {dp[j] = dp[j];} else {dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);}//System.out.print(dp[j]);}//System.out.println();//剪枝一下,每一次完成内层的for-loop,立即检查是否dp[target] == target,优化时间复杂度if (dp[target] == target) return true;}return dp[target] == target;//如果背包装满了,即能找到等和子集}
}

在这里插入图片描述

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

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

相关文章

基于Vue3与ElementUI Plus酷企秀可视化设计器中的创新应用

一、引言 随着科技的快速发展&#xff0c;前端技术已经从简单的网页呈现进化到了复杂的数据可视化、互动体验和跨平台应用的构建。酷企秀可视化设计器作为一个集成了多种前端技术的创新平台&#xff0c;不仅为企业提供了全方位的数字化展示解决方案&#xff0c;还在多个行业领…

SRC上分秘诀+实战挖掘+挖洞技巧+新手上路+详细讲解

SRC马上到来 可能有些好兄弟们还没有头绪 只会做一些靶场 并没有什么实战经验 所以这篇文章给大家分享一下我挖洞2个月的经验分享 适合新手上路 如何找站&#xff1f; 谷歌搜索 谷歌搜索 谷歌搜索 SQL注入XSS所有漏洞 inurl:.php?idxx 公司inurl:.asp?idxx 公司inurl:.jsp?…

Mysql基础篇(一)Mysql概述

目录 基本概念 数据库(DataBase,DB) 数据库的定义 数据库的分类 数据库管理系统(DataBase Management System,DBMS) SQL(Structured Query Language) Mysql Mysql数据模型 下载安装Mysql 基本概念 数据库(DataBase,DB) 数据库的定义 按照数据结构来组织、存储和管理数…

java报错:使用mybatis plus查询一个只返回一条数据的sql,却报错返回了1000多条

今天遇到一个问题 系统线上问题&#xff0c;经常出现这样的问题&#xff0c;刚重启系统时不报错了&#xff0c;可是运行一段时间又会出现。sql已经写了limit 1&#xff0c;mybatis的debug日志也返回total为1&#xff0c;可是却报错返回了1805条数据 乍一看&#xff0c;感觉太不…

汽车之家,如何在“以旧换新”浪潮中大展拳脚?

北京车展刚刚落幕&#xff0c;两重利好正主导汽车市场持续升温&#xff1a;新能源渗透率首破50%&#xff0c;以及以旧换新详细政策进入落地期。 图源&#xff1a;中国政府网 在政策的有力指引下&#xff0c;汽车产业链的各个环节正经历着一场深刻的“连锁反应”。在以旧换新的…

Python运维之多线程!!

一、多线程 二、多线程编程之threading模块 2.1、使用threading进行多线程操作有两种方法&#xff1a; 三、多线程同步之Lock&#xff08;互斥锁&#xff09; 四、多线程同步之Semaphore&#xff08;信号量&#xff09; 五、多线程同步之Condition 六、多线程同步之Event…

CSS和JavaScript

CSS 在html中引入CSS 我们需要先在该项目先建立css文件 html引入CSS,在<head></head>中添加<link>标签 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" co…

mac 本地使用docker 运行es,kibana

1.下载 m芯片一些版本不支持.踩过坑.翻看官网才知道只有部分镜像支持m芯片 https://hub.docker.com/添加链接描述 docker pull elasticsearch:7.17.21 docker pull kibana:7.17.21镜像已经下载下来了 2.创建文件映射-挂载 /Users/lin/dev/dockerMsg 其中lin是自己的用户名…

关于线程池,它的扩展问题你知道吗?(自己总结)

专门想一下为什么线程池不用Excutors&#xff0c;之前的印象是错的&#xff0c;居然还拿来面试里讲&#xff0c;惭愧&#xff0c;这里暂时整理俩小问题&#xff0c;其他的后续可能会更新。。 线程池是创建的越大越好嘛 #线程池创建的越大越好吗 Tip&#xff1a;2024-04-10 更…

本地搭建hydra服务用go以验证oidc流程

目录 1、docker搭建hydra&#xff0c;环境配置&#xff1a; 2、搭建完成后服务调用&#xff1a; 2.1保证服务正常启动&#xff1a; 2.2 通过postman调用&#xff0c;获取client_id&#xff1a; 2.3 通过client_id&#xff0c;实现oauth2/auth调用 3. 通过go语言实现oidc验…

【qt】容器的用法

容器目录 一.QVertor1.应用场景2.增加数据3.删除数据4.修改数据5.查询数据6.是否包含7.数据个数8.交换数据9.移动数据10.嵌套使用 二.QList1.应用场景2.QStringList 三.QLinkedList1.应用场景2.特殊点3.用迭代器来变量 四.QStack1.应用场景2.基本用法 五.QQueue1.应用场景2.基本…

OS复习笔记ch5-3

引言 上一节我们学习了关于信号量机制的一些内容&#xff0c;包括信号量的含义&#xff0c;对应的PV操作等。 如图所示&#xff0c;上一节主要是针对信号量的互斥&#xff0c;其实信号量机制还可以做很多事情&#xff0c;比如实现进程同步和前驱关系&#xff0c;这一节我们先复…

【Spring】JdbcTemplate

JdbcTemplate 是 Spring 提供的一个 JDBC 模板类&#xff0c;是对 JDBC 的封装&#xff0c;简化 JDBC 代码 也可以让 Spring 集成其它的 ORM 框架&#xff0c;例如&#xff1a;MyBatis、Hibernate 等 使用 JdbcTemplate 完成增删改查 一、环境准备 数据库&#xff1a; 准备…

Marin说PCB之如何快速打印输出整板的丝印位号图?

当小编我辛辛苦苦加班加点的把手上的板子做到投板评审状态的时候&#xff0c;坐在我旁边的日本同事龟田小郎君说让我把板子上的丝印也要调一下&#xff0c;我当时就急了&#xff0c;这么大的板子&#xff0c;将近1W多PIN 了都&#xff0c;光调丝印都要老半天啊&#xff0c;而且…

Docx文件误删除如何恢复?别再花冤枉钱了,4个高效恢复软件!

不管是工作还是学习&#xff0c;总是会与各种各样的文件打交道。文件量越多就越容易出现文件丢失、文件误删的情况。遇到这些情况&#xff0c;失去的文件还能找回来吗&#xff1f;只要掌握了一些数据恢复方法&#xff0c;是很有机会恢复回来的&#xff0c;下面我会将这些方法分…

[机器学习系列]深入探索回归决策树:从参数选择到模型可视化

目录 一、回归决策树的参数 二、准备数据 三、构建回归决策树 (一)拟合模型 (二)预测数据 (三)查看特征重要性 (四)查看模型拟合效果 (五) 可视化回归决策树真实值和预测值 (六)可视化决策树并保存 部分结果如下&#xff1a; 一、回归决策树的参数 DecisionTreeRegress…

NVIDIA_SMI has failed because it couldn’t communicate with the NVIDIA driver

参考&#xff1a;https://www.zhihu.com/question/474222642/answer/3127013936 https://blog.csdn.net/ZhouDevin/article/details/128265656 nvidia-smi查看报错&#xff0c;nvcc正常 1&#xff09;查看nvidia版本 ls /usr/src | grep nvidia nvidia-550.78 2&#xff09;…

暗区突围国际服pc端怎么获取测试资格 twitch掉落资格获取教程

《暗区突围》是由腾讯魔方工作室群开发的第一人称射击类手游。游戏以从暗区撤离并收集物资满载而归作为最终目的&#xff0c;带出的战利品可以存储在仓库中&#xff0c;又可以出售用以换取游戏金钱。游戏中玩家可以创建男性或女性角色&#xff0c;可以通过选择脸型、发型、发色…

C++ 动态内存管理

例如&#xff1a;动态内存和释放单个数据的存储区 一 用new运算符初始化单个数据的存储区 举例

【智能算法】人工原生动物优化算法(APO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.获取代码 1.背景 2024年&#xff0c;X Wang受到自然界原生动物启发&#xff0c;提出了人工原生动物优化算法&#xff08; Artificial Protozoa Optimizer, APO&#xff09;。 2.算法原理 2.1算法思想 AP…