首页 > 编程语言 >代码随想录算法训练营Day39 | 卡玛网-46.携带研究材料、416. 分割等和子集

代码随想录算法训练营Day39 | 卡玛网-46.携带研究材料、416. 分割等和子集

时间:2024-10-21 15:49:07浏览次数:3  
标签:背包 weight Day39 46 nums 随想录 int 数组 dp

目录

卡玛网-46.携带研究材料

416. 分割等和子集

卡玛网-46.携带研究材料

题目

卡玛网46. 携带研究材料(第六期模拟笔试)

题目描述:

小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。他需要带一些研究材料,但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等,它们各自占据不同的空间,并且具有不同的价值。

小明的行李空间为 N,问小明应该如何抉择,才能携带最大价值的研究材料,每种研究材料只能选择一次,并且只有选与不选两种选择,不能进行切割。

输入描述:

第一行包含两个正整数,第一个整数 M 代表研究材料的种类,第二个正整数 N,代表小明的行李空间。

第二行包含 M 个正整数,代表每种研究材料的所占空间。

第三行包含 M 个正整数,代表每种研究材料的价值。

输出描述:

输出一个整数,代表小明能够携带的研究材料的最大价值。

输入示例:

6 1
2 2 3 1 5 2
2 3 1 5 4 3

输出示例:

5

提示信息:

小明能够携带 6 种研究材料,但是行李空间只有 1,而占用空间为 1 的研究材料价值为 5,所以最终答案输出 5。

数据范围:
1 <= N <= 5000
1 <= M <= 5000
研究材料占用空间和价值都小于等于 1000

思路

代码随想录:背包理论基础-01背包-1

视频讲解1:带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!

代码随想录:背包理论基础-01背包-2

视频讲解2:带你学透01背包问题(滚动数组篇) | 从此对背包问题不再迷茫!

例子:

背包最大重量为4。

物品为:

重量价值
物品0115
物品1320
物品2430

二维数组:

动态规划五部曲:

1:确定dp数组以及下标含义:使用二维数组,两个维度分别表示物品和背包容量,纵向表示物品,横向表示背包容量:

动态规划-背包问题1

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

2:确定递推公式:求取dp[i][j]有两种情况,向背包中放入或者不放入物品 i,如果不放入物品 i,则当前情况下物品最大价值等于dp[i-1][j];如果放入物品 i,首先注意背包要留出物品 i 的容量,当前情况下物品最大价值等于dp[i - 1][j - weight[i]]+value[i]。因此,递推公式为dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]]+value[i])

3:初始化数组:首先,背包容量为 0 时,背包价值一定为0,因此初始化dp[i][0] = 0;由递推公式可知dp[i][j]需要从dp[i-1][j]进行推导,所以还要初始化i = 0的情况,当j < weight[i]时,初始化dp[0][j] = 0j > weight[i]时,初始化dp[0][j] = value[i]。其余下标的值最终都会被递推结果覆盖,所以初始化为任意值都可以。最终初始化情况如下:

动态规划-背包问题10

4:确定遍历顺序:由递归公式可知dp[i][j]由其左上角和正上方的两个下标决定,所以从左往右,从上往下遍历即可,选择先遍历物品,后遍历背包容量或者相反顺序都可以。

5:举例推导:

动态规划-背包问题4

滚动数组:

在二维数组遍历时可以将每一层的结果拷贝到下一层之中,然后递推公式也可以只在本层进行,等效于只使用了一个滚动数组保存结果。

动态规划五部曲:

1:确定dp数组以及下标含义:dp[j]表示容量为 j 的背包可以放入的最大的物品价值。

2:确定递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]),即在二维数组的公式基础上去掉 i 维度。

3:初始化数组:由于物品价值都大于0,为了不让初始值覆盖掉 dp 数组的取值,全部初始化为 0 即可。

4:确定遍历顺序:遍历时背包容量从大到小,为了保证每一个物品都只会被放入背包一次,如果使用正序遍历,每个物品都会被重复放入背包多次,可以写出正序遍历代码自己测试。

5:举例推导:

动态规划-背包问题9

题解

二维数组:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt(); // 研究材料的种类
        int N = scanner.nextInt(); // 行李空间
        int[] weight = new int[M]; // 每种研究材料所占空间
        int[] value = new int[M]; // 每种研究材料的价值
        for (int i = 0; i < M; i++) {
            weight[i] = scanner.nextInt();
        }
        for (int i = 0; i < M; i++) {
            value[i] = scanner.nextInt();
        }
        scanner.close();
        int[][] dp = new int[M][N + 1];
        //初始化dp数组
        for (int i = 0; i < M; i++) {
            dp[i][0] = 0;
        }
        for (int i = weight[0]; i < N + 1; i++) {
            dp[0][i] = value[0];
        }
        //从左到右,从上到下遍历
        for (int i = 1; i < M; i++) {
            for (int j = 1; j < N + 1; j++) {
                if (j - weight[i] >= 0) {
                    dp[i][j] = Math.max(dp[i - 1][j - weight[i]] + value[i], dp[i - 1][j]);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        System.out.println(dp[M - 1][N]);
    }
}

滚动数组:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt(); // 研究材料的种类
        int N = scanner.nextInt(); // 行李空间
        int[] weight = new int[M]; // 每种研究材料所占空间
        int[] value = new int[M]; // 每种研究材料的价值
        for (int i = 0; i < M; i++) {
            weight[i] = scanner.nextInt();
        }
        for (int i = 0; i < M; i++) {
            value[i] = scanner.nextInt();
        }
        scanner.close();
        int[] dp = new int[N + 1];
        for (int i = 0; i < M; i++) {
            for (int j = N; j > 0; j--) {
                if (j - weight[i] >= 0) {
                    dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
                }
            }
        }
        System.out.println(dp[N]);
    }
}

416. 分割等和子集

题目

416. 分割等和子集 - 力扣(LeetCode)

给你一个 只包含正整数非空 数组 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

思路

视频讲解:LeetCode:416.分割等和子集

代码随想录:416.分割等和子集

确定以下四点后才能在本题套用01背包模板:

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

动态规划五部曲:

  1. 确定dp数组以及下标的含义:dp[j] 表示容量为 j 的背包能放的最大物品价值,当dp[target] = target时,说明可以进行分割。
  2. 确定递推公式:套用01背包递推公式,dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
  3. 初始化数组:数组元素全都初始化为0。
  4. 确定遍历顺序:遍历物品的 for 循环放在外层,遍历背包的 for 循环放在内层,且内层 for 循环倒序遍历。
  5. 举例推导:

416.分割等和子集2

题解

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int i : nums)
            sum += i;
        if (sum % 2 == 1)
            return false;
        int target = sum / 2;
        int[] dp = new int[target + 1];
        for (int i = 0; i < nums.length; i++) {
            for (int j = target; j > 0; j--) {
                if (j >= nums[i]) {
                    dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
                }
                if (dp[target] == sum / 2)
                    return true;
            }
        }
        return false;
    }
}

0; j–) {
if (j >= nums[i]) {
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
}
if (dp[target] == sum / 2)
return true;
}
}
return false;
}
}


标签:背包,weight,Day39,46,nums,随想录,int,数组,dp
From: https://blog.csdn.net/jiabao0520/article/details/143114790

相关文章

  • 代码随想录算法训练营第六天| leetcode242.有效的字母异位词、leetcode349.两个数组的
    1.leetcode242.有效的字母异位词题目链接:242.有效的字母异位词-力扣(LeetCode)文章链接:代码随想录视频链接:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词_哔哩哔哩_bilibili自己的思路:首先就是对字符串进行分开成一个一个单独的字母,然后使用列表存储这些数据,再对......
  • Springboot计算机毕业设计毕设课题的选择和申报管理系统2u465
    Springboot计算机毕业设计毕设课题的选择和申报管理系统2u465本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能:专业,班级,学生,教师,通知类型,通知公告,学院,课题类型,课题信息,选题信息,论文信息,论文......
  • 代码随想录算法训练营 | 739. 每日温度,496.下一个更大元素 I ,503.下一个更大元素II
    739.每日温度题目链接:739.每日温度文档讲解︰代码随想录(programmercarl.com)视频讲解︰每日温度日期:2024-10-20想法:遍历一遍数组,用栈来存数组下标做记录,因为要找更高得温度,当当前遍历的温度大于栈头存储(存的下标)的温度时,就可以知道栈头要过多少天遇到高温,低的时候直接入栈。J......
  • [1468]基于JAVA的户外用品销售智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的户外用品销售智慧管理系统的设计与实现指导老师(一)选题的背景和意义选题背景与意义:在当今信息化社会,随着户外活动的日益普及和消费者对户外用品需求的持续增长,户外用品销售行业面临着巨大的市场机遇和管理挑战。......
  • 基于Java的流浪动物领养系统 毕业设计-附源码 97463
    目 录1绪论1.1研究背景与意义1.2国内外研究现状1.3论文结构与章节安排2 系统分析2.1可行性分析2.1.1技术可行性分析2.1.2 经济可行性分析2.1.3法律可行性分析2.2系统功能分析2.2.1功能性分析2.2.2非功能性分析2.3 系统用例分析2.4 ......
  • 代码随想录算法训练营第五天| 面试题02.07.链表相交、leetcode142 环形链表II
    1.leetcode面试题02.07.链表相交题目链接:面试题02.07.链表相交-力扣(LeetCode)文章链接:代码随想录1.1代码跟着老师写的一个版本,自己能理解思路了,但是写的话可能还是有一些难#Definitionforsingly-linkedlist.#classListNode:#def__init__(self,x):#......
  • 代码随想录|回溯part 01
    存在于递归函数的下方,递归与回溯相辅相成回溯搜索法:暴力算法适用范围:•组合问题:N个数里面按一定规则找出k个数的集合(无序)•切割问题:一个字符串按一定规则有几种切割方式•子集问题:一个N个数的集合里有多少符合条件的子集•排列问题:N个数按一定规则全排列,有几种排列方......
  • 代码随想录算法训练营day20| 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树
    学习资料:https://programmercarl.com/0669.修剪二叉搜索树.html#算法公开课学习记录:669.修剪二叉搜索树(直接在原函数上操作,要根据情况用root的左右子树递归,因为子树中有满足条件的;前序:根左右)点击查看代码#Definitionforabinarytreenode.#classTreeNode:#def_......
  • 代码随想录算法训练营 | 647. 回文子串,516.最长回文子序列
    647.回文子串题目链接:647.回文子串文档讲解︰代码随想录(programmercarl.com)视频讲解︰回文子串日期:2024-10-19想法:本题精髓在于dp[i][j]表示的是s[i,j]这个子字符串是不是回文的,是Boolean类型,s[i]s[j]不等时,肯定不回文;s[i]s[j]相等时,开始看ij的大小,ij大小相等那么表示单个字......
  • 代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点
    1.leetcode24两两交换链表中的节点题目链接:24.两两交换链表中的节点-力扣(LeetCode)文章链接:代码随想录(programmercarl.com)视频链接:帮你把链表细节学清楚!|LeetCode:24.两两交换链表中的节点_哔哩哔哩_bilibili1.1代码这个代码是用循环的思路来进行判断的,写的过程挺......