D36|背包问题

        从图中我们可以看出背包问题主要涉及01背包完全背包、多重背包和分组背包。 


01背包问题

1.暴力解法是一个回溯问题

2.动态规划方法涉及二维dp数组和一维dp数组解法,二维dp数组是1维dp数组的基础

二维dp数组解法:

首先考虑动态规划五部曲

1)dp数组的定义:

        dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少

        此处一定要注意i表示的是一个范围

2)递推公式:

         dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

3)如何初始化:

vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
for (int j = weight[0]; j <= bagweight; j++) {dp[0][j] = value[0];
}

也就是从容量大于weight[0]开始初始化到背包最大容量。

4)遍历顺序

        先遍历 物品还是先遍历背包重量呢 

        均可,先遍历物品更容易理解

// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) { // 遍历物品for(int j = 0; j <= bagweight; j++) { // 遍历背包容量if (j < weight[i]) dp[i][j] = dp[i - 1][j];else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);}
}

5)举例推导递推数组。

卡码网46题

import java.util.Scanner;
public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int numofthings = sc.nextInt();int weight = sc.nextInt();int[] we = new int[numofthings];int[] value = new int[numofthings];for(int i = 0;i<numofthings;i++){we[i] = sc.nextInt();}for(int i = 0;i<numofthings;i++){value[i] = sc.nextInt();}// System.out.println("num"+numofthings);// System.out.println("weight"+weight);// System.out.println(Arrays.toString(we));// System.out.println(Arrays.toString(value));System.out.println(bagsolution(numofthings,weight,we,value));}public static int bagsolution(int num,int weight,int[] we,int[]value){int[][] dp = new int[num][weight+1];//初始化for(int i = we[0];i<=weight;i++){dp[0][i] = value[0];}//开始遍历for(int i = 1;i<num;i++){for(int j = 1;j<weight+1;j++){if(we[i]>j){dp[i][j] = dp[i-1][j];}else{dp[i][j] = Math.max(dp[i-1][j],(dp[i-1][j-we[i]]+value[i]));}}}return dp[num-1][weight];}
}

 


一维DP数组解法(滚动数组):

动态规划五部曲:

1)dp数组的定义:

        dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

2)递归公式:

dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

3)初始化:

     dp数组初始化的时候,都初始为0。

4)遍历顺序:

        j是倒序遍历,保证每个物品只添加一次

for(int i = 0; i < weight.size(); i++) { // 遍历物品for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}
}

 同时必须保证先遍历物品再遍历容量。

如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品。

比如在dp[4]中

dp[4] = Math.max(dp[4],dp[1]+value[1])此时,dp[1]还没有装入物品0,所以相当于仅放入了物品1.

5)举例推导dp数组


416.分割等和子集

初始思路:

首先求和,如果和/2是一个小数的话那么肯定不可分

然后就是联想,如何把该题转化为01背包问题呢?

物品 数组中的数

物品的重量 数组的值

物品的价值 数组的值

weight = sum/2;

如果在背包问题中有dp【j】 = weight;就代表可分

class Solution {public boolean canPartition(int[] nums) {double sum = 0;for (int i = 0; i < nums.length; i++) {sum = sum+ nums[i];}//System.out.println(sum);double weight = sum/2;//System.out.println(weight);int integerPart = (int) weight; // 取整数部分if (weight != integerPart) {//System.out.println("该数是一个小数");return false;} else {//System.out.println("该数不是一个小数");int[] dp = new int[integerPart+1];for(int i = 0;i<nums.length;i++){for(int j=integerPart;j>=nums[i];j--){dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);if(dp[j]==integerPart){return true;}}}}return false;}
}

 题解复盘:

只有确定了如下四点,才能把01背包问题套到本题上来。

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

动规五部曲分析如下:

1.确定dp数组以及下标的含义

01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。

本题中每一个元素的数值既是重量,也是价值。

套到本题,dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]

那么如果背包容量为target, dp[target]就是装满 背包之后的重量,所以 当 dp[target] == target 的时候,背包就装满了。

2.确定递推公式

所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);

3.dp数组如何初始化

非0下标的元素初始化为0

4.确定遍历顺序

注意条件一定是j>=nums[i]!

// 开始 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]);}
}

5.举例推导dp数组

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

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

相关文章

鸿蒙-arkTs:访问控制授权申请

module.json5文件中 requestPermissions 进行配置&#xff08;值为数组&#xff0c;可配置多个&#xff09; ohos.permission.INTERNET {"name": "ohos.permission.INTERNET" }

解除Java反复编译的困扰方法,优化开发效率

在Java开发过程中&#xff0c;反复编译是一个常见的问题&#xff0c;特别是在大型项目或者需要频繁修改代码的情况下。每次修改代码后都需要重新编译整个项目&#xff0c;这样耗费了大量的时间和资源&#xff0c;降低了开发效率。为了解决这个问题&#xff0c;我们可以采取以下…

EPICS asynPortDriver使用示例

在文本中&#xff0c;将展示如何将EPICS asyn模块和其他库联用&#xff0c;从而实现对arm单板机上GPIO口的控制。 在本例中使用到的硬件是&#xff1a; 在程序中需要厂家提供的wringPi库&#xff0c;才能通过C语言库函数调用实现对其GPIO的控制。 以下是这个单板机GPIO的管脚…

手动搭建koa+ts项目框架(swagger文档篇)

文章目录 一、安装依赖二、直接使用json文件生成三、根据对应api注释生成新建swagger.ts文件新建./routes/users.ts文件入口文件引入对应数据如有启发&#xff0c;可点赞收藏哟~ 一、安装依赖 swagger-jsdoc 读取您的JSDoc带注释的源代码并生成OpenAPI (Swagger) 规范koa2-swa…

意大利语文章翻译成中文怎么收费?

随着全球化的步伐加快&#xff0c;不同语言之间的交流日益频繁&#xff0c;其中意大利语翻译成中文的需求逐渐增多。那么&#xff0c;意大利语文章翻译成中文该如何收费呢&#xff1f;又在哪里能找到专业的意大利语翻译呢&#xff1f; 翻译是将一种语言文字转化为另一种语言文字…

Android:安卓学习笔记之OkHttp原理的简单理解和使用

Android OkHttp使用原理的简单理解和使用 OkHttp 0、前言1、请求与响应流程 1.1 请求的封装1.2 请求的发送1.3 请求的调度1.4 请求的处理2、拦截器 2.1 RetryAndFollowUpInterceptor2.2 BridgeInterceptor2.3 CacheInterceptor 2.3.1、HTTP缓存原理2.3.2、强制缓存2.3.3、协商…

Oracle迁移乾坤大挪移,用它轻松拿捏!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

智能 GPT 图书馆又重生了

智能 GPT 图书馆又重生了 作者&#xff1a;程序员小白条 1&#xff09;概述 自从大二寒假准备开始筹备这个项目&#xff0c;到现在已经一年了&#xff0c;这个项目能维护一年&#xff0c;不愧是我.jpg。本来这个项目只是想练练手&#xff0c;因为那时候刚学完 Spring Boot2 V…

macOS 安装 oh-my-zsh 后 node 报错 command not found : node

最近为了让终端中显示 git 分支的名称&#xff0c;安装了 oh-my-zsh &#xff0c;安装之后呢&#xff0c;我原先安装的 Volta、 node 都没法用了&#xff0c;报错如下&#xff1a; 这时候粗略判断应该是系统变量出了问题&#xff0c;oh-my-zsh 的变量文件是 ~/.zshrc&#xff0…

【数据结构】单链表的定义和操作

目录 1.单链表的定义 2.单链表的创建和初始化 3.单链表的插入节点操作 4.单链表的删除节点操作 5.单链表的查找节点操作 6.单链表的更新节点操作 7.完整代码 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助…

互式流程图|BPMN JointJS+ JavaScript 3.7.3 Crack

JointJS 是 JavaScript 图表库为卓越的 UI 提供支持 使用经过验证的库快速、自信地构建高级视觉和无代码/低代码应用程序。 赋能全球行业领导者 使用 JointJS 构建的图表 一个库&#xff0c;‍无限 UI 选项 直接在您的应用程序中享受交互式流程图、BPMN 和其他图表工作室。利用…

如何同时给每张PPT插入不同的图片?这2种方法可行!

有时候创作PPT&#xff0c;我们需要把几十张图片插入到PowerPoint中&#xff0c;每张图片作为一张幻灯片&#xff0c;如果一张张手动操作&#xff0c;那就未免太花时间了。今天小编来分享2种方法&#xff0c;可以让您快速给每张PPT插入不同图片。 方法一、使用“创建相册” 1.…