算法训练营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!

相关推荐
ALISHENGYA5 分钟前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法
guogaocai1237 分钟前
连续自成核退火热分级(SSA)技术表征共聚聚丙烯(PP)分子链结构
算法
DARLING Zero two♡31 分钟前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
游是水里的游1 小时前
【算法day19】回溯:分割与子集问题
算法
不想当程序猿_1 小时前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
南城花随雪。2 小时前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
dundunmm2 小时前
机器学习之scikit-learn(简称 sklearn)
python·算法·机器学习·scikit-learn·sklearn·分类算法
古希腊掌管学习的神2 小时前
[机器学习]sklearn入门指南(1)
人工智能·python·算法·机器学习·sklearn
波音彬要多做2 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
程序员老冯头4 小时前
第十五章 C++ 数组
开发语言·c++·算法