day42 动态规划part4

news2024/11/19 19:18:40

先遍历物品还是先遍历背包二刷再考虑吧。累了,不想停留太久。

在这里插入图片描述

背包问题 二维 (卡码网题目)

在这里插入图片描述

各种解释:

要理解的是这个表格每一个格子都是当前所处情况的最大价值,我们用已经推导出的最大价值来推导当前情况的最大价值。
在这里插入图片描述
在这里插入图片描述

package DP;

// i-1是指能选择的物品有i-1个而不一定真的放了i-1个物品
// dp【i】【j】 表示背包容量为 j 时,从 0..i 类物品种选取,可以获得的最大价值
// 如果有的朋友不理解对放物品i时为什么要是 j - weight【i】,这里可以理解为背包需要留出这个物品i的容量才可以放物品i
public class BagProblem {
    public static void main(String[] args) {
        int[] weight = {4,3,1};
        int[] value = {30,20,15};
        int bagSize = 4;
        testWeightBagProblem(weight,value,bagSize);
    }

    public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){
        int[][] dp = new int [weight.length][bagSize + 1];

        // 初始化dp数组
        /**
     * 初始化 dp 数组做了简化(给物品增加冗余维)。这样初始化dp数组,默认全为0即可。
     * dp[i][j] 表示从下标为[0 - i-1]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
     * 其实是模仿背包重量从 0 开始,背包容量 j 为 0 的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为 0。
     * 可选物品也可以从无开始,也就是没有物品可选,即dp[0][j],这样无论背包容量为多少,背包价值总和一定为 0。
     * @param weight  物品的重量
     * @param value   物品的价值
     * @param bagSize 背包的容量
     */
        // 创建数组后,其中默认的值就是0
        for (int j = weight[0]; j <= bagSize; j++) {
            dp[0][j] = value[0];
        }

        // 填充 dp 数组
        for (int i = 1; i < weight.length; i++) {
            for (int j = 1; j <= bagSize; j++) {
                if (j < weight[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 - weight[i]] + value[i]);
                }
                // 打印dp数组(自己整个数组试试就知道了)
                System.out.println("i = " + i + "\t" + "j = " + j);
                for (int k = 0; k < weight.length; k++) {
                    for (int z = 0; z <= bagSize; z++) {
                        System.out.print(dp[k][z] + "\t");
                    }
                    System.out.println("\n");
                }
            }
        }
    }

}

背包问题 一维(滚动数组) (卡码网题目,和上面那个题目是一样的)

难点在于,把二维数组变成了一维,相当于把上一行的数据复制到了下一行,不断滚动。最大的差异在于,遍历的顺序变成了从后往前,其实是没问题的,因为算本行数据只需要用到上一行的数据,本行前面的数据用不上,所以可以从后往前。倒序的时候左边元素再刷新前都是上一层的数据,但正序就不一样了,正序的时候,左边的元素刚刚刷新过,也就是左边的元素已经是本层的了,意味着什么 这样会导致一个物品反复加好几次。具体解释见下面截图:

在这里插入图片描述

难点:初始化也变了,因为从后往前遍历,所以可以内化到for循环里去。一维和二维的初始化其实是一个道理。你可以理解成二维数组初始化的时候,在物品0上面还有一个物品-1代表一个重量和价值都等于0的物体。 dp[j - weight[i]] 为什么不会越界?因为for循环里写了j > = weight[i] !!!

在这里插入图片描述

for循环中途有一个条件不满足会直接退出,如下演示:

在这里插入图片描述

 public static void main(String[] args) {
        int[] weight = {1, 3, 4};
        int[] value = {15, 20, 30};
        int bagWight = 4;
        testWeightBagProblem(weight, value, bagWight);
    }

    public static void testWeightBagProblem(int[] weight, int[] value, int bagWeight){
        int wLen = weight.length;
        //定义dp数组:dp[j]表示背包容量为j时,能获得的最大价值
        int[] dp = new int[bagWeight + 1];
        //遍历顺序:先遍历物品,再遍历背包容量
        for (int i = 0; i < wLen; i++){
            for (int j = bagWeight; j >= weight[i]; j--){
                dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
            }
        }
        //打印dp数组
        for (int j = 0; j <= bagWeight; j++){
            System.out.print(dp[j] + " ");
        }
    }

416. 分割等和子集

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

难点:这道题目就是一道01背包应用类的题目,需要我们拆解题目,然后套入01背包的场景。01背包相对于本题,主要要理解,题目中物品是nums[i],重量是nums[i],价值也是nums[i],背包体积是sum/2。就相当于,给你一个体积为sum/2的背包,让你挑选一种放东西的方法,使得放的东西最多,最多是多少,当然是放满,也就是sum/2,如果没放这么多,说明就是放不满,返回false。

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int num : nums) sum += num;
        if (sum % 2 == 1) return false; // 和为奇数,不可等分

        int dp[] = new int [sum / 2 + 1];

        for (int i = 0; i < nums.length; i++) {
            for (int j = dp.length - 1; j >= nums[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
            }
        }

        return dp[dp.length - 1] == sum / 2;
    }
}
public class Solution {
    public static void main(String[] args) {
        int num[] = {1,5,11,5};
        canPartition(num);

    }
    public static boolean canPartition(int[] nums) {
        int len = nums.length;
        // 题目已经说非空数组,可以不做非空判断
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        // 特判:如果是奇数,就不符合要求
        if ((sum %2 ) != 0) {
            return false;
        }

        int target = sum / 2; //目标背包容量
        // 创建二维状态数组,行:物品索引,列:容量(包括 0)
        /*
        dp[i][j]表示从数组的 [0, i] 这个子区间内挑选一些正整数
          每个数只能用一次,使得这些数的和恰好等于 j。
        */
        boolean[][] dp = new boolean[len][target + 1];

        // 先填表格第 0 行,第 1 个数只能让容积为它自己的背包恰好装满  (这里的dp[][]数组的含义就是“恰好”,所以就算容积比它大的也不要)
        if (nums[0] <= target) {
            dp[0][nums[0]] = true;
        }
        // 再填表格后面几行
        //外层遍历物品
        for (int i = 1; i < len; i++) {
            //内层遍历背包
            for (int j = 0; j <= target; j++) {
                // 直接从上一行先把结果抄下来,然后再修正
                dp[i][j] = dp[i - 1][j];

                //如果某个物品单独的重量恰好就等于背包的重量,那么也是满足dp数组的定义的
                if (nums[i] == j) {
                    dp[i][j] = true;
                    continue;
                }
                //如果某个物品的重量小于j,那就可以看该物品是否放入背包
                //dp[i - 1][j]表示该物品不放入背包,如果在 [0, i - 1] 这个子区间内已经有一部分元素,使得它们的和为 j ,那么 dp[i][j] = true;
                //dp[i - 1][j - nums[i]]表示该物品放入背包。如果在 [0, i - 1] 这个子区间内就得找到一部分元素,使得它们的和为 j - nums[i]。
                if (nums[i] < j) {
                    dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
                }
            }
        }
        for (int i = 0; i < len; i++) {
            for (int j = 0; j <= target; j++) {
                System.out.print(dp[i][j]+" ");
            }
            System.out.println();
        }
        return dp[len - 1][target];
    }
}

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

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

相关文章

2.案例、鼠标时间类型、事件对象参数

案例 注册事件 <!-- //disabled默认情况用户不能点击 --><input type"button" value"我已阅读用户协议(5)" disabled><script>// 分析&#xff1a;// 1.修改标签中的文字内容// 2.定时器// 3.修改标签的disabled属性// 4.清除定时器// …

GUROBI之数学启发式算法Matheuristics

参考运小筹的帖子&#xff1a;优化求解器 | Gurobi 数学启发式算法&#xff1a;参数类型与案例实现 - 知乎 (zhihu.com) 简言之&#xff0c;数学启发式是算法就是数学规划和启发式算法的融合&#xff0c;与元启发式算法相比&#xff0c;数学启发式算法具有更强的理论性。 在GUR…

WEB区块链开发组件 - KLineChart

当我们开发区块链的时候&#xff0c;实现K线可能大家会想到EChart&#xff0c;但是EChart做可能需要耗费大量工作量&#xff0c;实现出来的功能估计也是牵强着用。 这时候&#xff0c;我们可能网上会搜索到TradingView,可是这个组件虽然功能非常强大&#xff0c;但是还是要费事…

视觉图像处理和FPGA实现第三次作业--实现一个加法器模块

一、adder模块 module adder(ina, inb, outa); input [5:0] ina ; input [5:0] inb ; output [6:0] outa ;assign outa ina inb; endmodule二、add模块 module add(a,b,c,d,e); input [5:0] a ; input [5:0] b ; input [5:…

Matlab R2021a安装教程(附带免费安装包)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 Matlab简介 Matlab是一种高级技术计算语言和交互式环境&#xff0c;用于算法开发、数据可视化和数值计算。它集成了数学、工程和科…

unity中实现场景跳转

1&#xff0c;第一步创建2个场景&#xff08;右键资源窗口&#xff0c;名字这里我取的1111和2222&#xff09; 2.添加跳转按钮&#xff08;双击其中一个场景并添加按钮&#xff09; 3.编辑按钮的文字&#xff08;将原本的按钮打开点击里面的text&#xff0c;就可以在右边编辑文…

MySQL 多种日期处理函数介绍

MySQL 提供了多种日期处理函数&#xff0c;用于处理和操作日期和时间数据。这些函数可以帮助你执行如日期计算、时间转换、格式化输出等操作。以下是一些常用的 MySQL 日期处理函数及其用法&#xff1a; 日期和时间格式化函数 1. **DATE_FORMAT()**&#xff1a;将日期或时间戳格…

AI壁纸号一周增加上千粉丝,轻松变现的成功案例分享

前言 随着AI绘画技术的发展&#xff0c;传统的互联网副业壁纸号在新的技术加持下迎来了第二春。本文将分享一位壁纸号创作者的成功案例&#xff0c;并为大家提供创作门槛和硬件要求等相关信息。 该项目的创作门槛极低&#xff0c;基本上可以由AI完成内容创作。不过&#xff0…

使用python实现一个dicom影像解析入库程序demo

简介 DICOM&#xff08;Digital Imaging and Communications in Medicine&#xff09;是医学图像和相关信息的国际标准。它定义了医学影像的格式和通信协议&#xff0c;使得不同设备和系统之间可以交换和共享医学图像和相关数据&#xff0c;如CT扫描、MRI图像、超声波图像等。…

代码随想录算法训练营第七天| 454.四数相加II、383.赎金信、15.三数之和、18.四数之和

系列文章目录 目录 系列文章目录454.四数相加II使用HashMap法 383.赎金信哈希解法&#xff08;数组&#xff09; 15.三数之和双指针法 18.四数之和双指针法 454.四数相加II 题解&#xff1a;该题和1.两数之和的方法是一样的&#xff0c;这个题的难点在于key和value分别是什么。…

发那科数控机床FanucCNC(NCGuide)仿真模拟器配置和数据采集测试

开发日记3.12 此篇用于记录发那科数控机床(Fanuc CNC)采集程序开发中&#xff0c;用虚拟机做测试时&#xff0c;虚拟机的配置和使用以支持采集软件开发和测试。 配置虚拟机使用仿真软件 下载VMware15 「链接&#xff1a;https://pan.xunlei.com/s/VNsl9Gmb14ANBiiNlsT7vA2LA…

Day15 面向对象进阶——接Day14

Day15 面向对象进阶——接Day14 文章目录 Day15 面向对象进阶——接Day14一、访问修饰符二、Object三、深入String的equals()方法四、final 一、访问修饰符 1、含义&#xff1a;修饰类、方法、属性&#xff0c;定义使用的范围 2、经验&#xff1a; 2.1.属性一般使用private修…

springboot3 打包报错32-bit architecture x86 unsupported或者 returned non-zero result

springboot3 打包异常情况处理记录 在测试springboot3 native打包时候遇到的异常&#xff0c;百度和谷歌上方法都无法解决我的问题&#xff0c;最后记录一下我最后的原因和解决方案。 前置要求&#xff1a;自己处理好vs的相关内容后 报错一&#xff1a; [1/7] Initializing…

Vue3 前端生成随机id( 生成 UUID )

效果展示 封装工具&#xff08;代码展示&#xff09; 重新创建一个文件**/utils/someTools.js**&#xff0c;并在里面写入如下代码。 function Tools() {}Tools.prototype.guid function () {return xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx.replace(/[xy]/g, function (c) {v…

Android SDK 开发 云托管

开发SDK,拒绝重复造轮子。 本文陈述两种SDK开发方式&#xff0c;第一种AAR方式&#xff1b;第二种远程依赖方式。 具体步骤分为&#xff1a; 一、如何开发SDK&#xff1f; 二、如何打包AAR&#xff1f; 三、如何打包AAR&#xff1f; 四、如何进行SDK远程托管&#xff1f; 五、如…

工业物联网平台在水务环保、暖通制冷、电力能源等行业的应用

随着科技的不断发展&#xff0c;工业物联网平台作为连接物理世界与数字世界的桥梁&#xff0c;正逐渐成为推动各行业智能化转型的关键力量。在水务环保、暖通制冷、电力能源等行业&#xff0c;工业物联网平台的应用尤为广泛&#xff0c;对于提升运营效率、降低能耗、优化管理等…

toJSONString空值被忽略解决办法 toJSONString过程中时间格式丢失问题解决办法

toJSONString空值被忽略解决办法 原代码&#xff1a; GcGarbageBuildingDO data gcGarbageBuildingService.get(id); result.putAll(JSON.parseObject(JSON.toJSONString(data), Map.class));查询出来的data中部分字段值为null&#xff0c;在toJSONString的过程中会把null值…

基于STM32的感应开关垃圾桶

1.定时器介绍 1.1 工作原理 使用精准的时基&#xff0c;通过硬件的方式&#xff0c;实现定时功能。 1.2 定时器分类 基本定时器&#xff08;TIM6~TIM7&#xff09;通用定时器&#xff08;TIM2~TIM5&#xff09;高级定时器&#xff08;TIM1和TIM8&#xff09; 1.3 通用定时器…

【C语言】Windows下的C语言线程编程详解

文章目录 1. 头文件1.1 windows.h1.2 process.h 2. 创建线程3. 线程同步3.1 线程同步方式3.1 互斥量&#xff08;Mutex&#xff09;3.2 事件&#xff08;Event&#xff09; 4. 线程的结束与资源管理5.线程池&#xff08;简要&#xff09; 在Windows平台下&#xff0c;C语言提供…

隧道技术和代理技术(三)

隧道技术 知识点 -隧道技术&#xff1a;解决不出网协议上线的问题&#xff08;利用出网协议进行封装出网&#xff09; -代理技术&#xff1a;解决网络通讯不通的问题&#xff08;利用跳板机建立节点后续操作&#xff09; 内环境示意图&#xff0c;方便理解 思路&#xff1a;…