算法训练营Day36

#Java #动态规划

开源学习资料

Feeling and experiences:

动态规划:01背包理论基础:卡码网题目链接

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

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

经典背包问题:

01 背包

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

java 复制代码
import java.util.*;

public class Main{
    
    public static void main(String[] args){
        //现根据题目写出输入
        
        Scanner sc = new Scanner(System.in);
        
        int M = sc.nextInt();
        int N = sc.nextInt();
        
        int[] values = new int[M];
        int[] weights = new int[M];
        
        //给数组赋值
        for(int i = 0;i < M;i++){
            weights[i] = sc.nextInt();
        }
        
        for(int i =0;i < M;i++){
            values[i] = sc.nextInt();
        }
        
        //创建dp数组
        int [][]dp = new int[M][N+1];
        
        //初始化dp数组
        for(int i = weights[0];i <= N;i++){
            dp[0][i] = values[0];
        }
        
        //遍历 递推
        for(int i = 1;i < M;i++){
            for(int j =0;j<=N;j++){
                if(weights[i] > j){
                    dp[i][j] = dp[i-1][j];
                }else{
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weights[i]] + values[i]);
                }
            }
        }
        System.out.println(dp[M-1][N]);
    }
}

notice:卡码网代码需要写输入代码。

初始化dp数组:

这个循环初始化了dp数组的第一行,设定了只考虑第一个物品(索引为0)时的情况。

如果第一个物品的重量(假设为10)小于等于背包的当前容量(i),则这个背包能够装下这个物品,因此dp[0][i](考虑第一个物品且背包容量为i时的最大价值)被设置为该物品的价值values[0]。
对于不能装下第一个物品的情况(即i < weights[0]),dp[0][i]默认为0(Java中数组的初始值)。

递推公式:

外循环遍历物品(从第二个开始,因为第一个已经在初始化时考虑过了)。
内循环遍历所有可能的背包容量。
如果当前物品的重量大于背包的当前容量(weights[i] > j),那么这个物品无法被加入,因此最大价值与前一个物品时相同(即dp[i][j] = dp[i-1][j])。
如果可以加入这个物品,我们需要决定是加入这个物品还是不加入。我们比较不加入这个物品时的最大价值(dp[i-1][j])和加入这个物品后的总价值(dp[i-1][j-weights[i]] + values[i])。

分割等和子集:力扣题目链接

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

示例 1:

复制代码
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

抽象成背包问题,确实没有想到~

  1. 初始检查:

• 检查数组长度是否小于2,如果是,直接返回false,因为无法分割成两个子集。

• 计算数组的总和sum和最大元素maxNum。

  1. 总和的奇偶性检查:

• 如果sum是奇数,不能分割成两个和相等的子集,返回false。

  1. 目标值设置:

• 将目标值设置为sum / 2。如果能找到和为target的子集,另一个子集自然也是target。

  1. 最大元素检查:

• 如果任何单个元素大于target,则无法分割,返回false。

  1. 动态规划表dp初始化:

• 创建一个布尔类型的二维动态规划表dp。dp[i][j]表示考虑前i个数字时,是否存在一个子集的和为j。

• 初始化所有dp[i][0]为true,因为不选择任何数字时,子集和为0。

• 将dp[0][nums[0]]设置为true,表示考虑第一个数字时,能达到的和为nums[0]。

  1. 动态规划计算:

• 对于每个元素num和每个目标和j,更新dp表。

• 如果j大于或等于当前数字num,则检查:

• 不包含当前数字(dp[i - 1][j])。

• 包含当前数字(dp[i - 1][j - num]),意味着我们从j中减去当前数字的值,查看剩余值是否可以由前i-1个数字组成。

• 更新dp[i][j]为这两种情况的逻辑或(|)结果。

java 复制代码
class Solution {
    public boolean canPartition(int[] nums) {
        int n = nums.length;
        if (n < 2) {
            return false;
        }
        int sum = 0, maxNum = 0;
        for (int num : nums) {
            sum += num;
            maxNum = Math.max(maxNum, num);
        }
        if (sum % 2 != 0) {
            return false;
        }
        int target = sum / 2;
        if (maxNum > target) {
            return false;
        }
        boolean[][] dp = new boolean[n][target + 1];
        for (int i = 0; i < n; i++) {
            dp[i][0] = true;
        }
        dp[0][nums[0]] = true;
        for (int i = 1; i < n; i++) {
            int num = nums[i];
            for (int j = 1; j <= target; j++) {
                if (j >= num) {
                    dp[i][j] = dp[i - 1][j] | dp[i - 1][j - num];
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[n - 1][target];
    }
}

Fighting!

相关推荐
YiHanXii4 分钟前
Java中 LinkedList<>,ArrayDeque<>的区别 || Queue和Deque的区别
java·算法
做人不要太理性10 分钟前
C++:基于红黑树封装map和set
开发语言·数据结构·c++·算法·set·map·红黑树
luckilyil32 分钟前
Java在算法竞赛中的常用方法
java·算法
小灰灰爱代码1 小时前
Python——鸡兔同笼问题
开发语言·python·算法
kali-Myon6 小时前
ctfshow-web入门-JWT(web345-web350)
前端·学习·算法·web安全·node.js·web·jwt
神洛华8 小时前
datawhale11月组队学习 模型压缩技术3:2:4结构稀疏化BERT模型
深度学习·算法·bert
南宫生8 小时前
力扣-Hot100-二叉树其二【算法学习day.33】
java·数据结构·学习·算法·leetcode·动态规划
trueEve9 小时前
SQL,力扣题目1126,查询活跃业务
算法·leetcode·职场和发展
别开生面的阿杰9 小时前
蓝桥杯-洛谷刷题-day3(C++)
c++·算法·蓝桥杯
Mr.W.T9 小时前
JVM垃圾回收详解(重点)
java·jvm·算法