首页 > 编程语言 >代码随想录算法训练营 | 背包问题 二维,背包问题 一维,416. 分割等和子集

代码随想录算法训练营 | 背包问题 二维,背包问题 一维,416. 分割等和子集

时间:2024-10-09 22:48:43浏览次数:1  
标签:背包 scanner weight int 随想录 value 416 dp

背包问题 二维
题目链接:背包问题 二维
文档讲解︰代码随想录(programmercarl.com)
视频讲解︰背包问题 二维
日期:2024-10-09

想法:dp[i][j],i表示需要从物品0-i中选择加入到背包中,j表示背包的容量,dp值表示最大的价值;
递推公式,如果背包大小j都比此时要放的物品i的weight[i]小了,背包放不下物品i了,此时最大的价值就是上一个物品i-1的最大价值了即dp[i-1][j]; j>weight[i]时,j-weight表示将此时i的重量腾出来,而此时dp[i - 1][j-weight]大小就是空出物品i空间后的最大价值,加上value[i]就知道了dp[i][j]的一个可能值,当然还要跟dp[i-1][j]比一下大小,如果放了物品i价值更低了呢,所以递推公式就是dp[i][j] = Math.max(dp[i - 1][j - weight[i]] + value[i], dp[i - 1][j]);
初始化j=0时背包放不了任何东西,价值为0,即dp二维数组第一列初始化为0,第一行背包容量大于等于weight[0]时才能将物品0放入背包,即放入价值value[0],否则都是价值0;
遍历顺序:第一行第一列都初始化好了,从i=1,j=1开始,最后返回dp右下角值就行了
Java代码如下:

import java.util.Scanner;

public class  Main {
    public static void main (String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        int bagweight = 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 j = 0; j < M; j++) {
            value[j] = scanner.nextInt();
        }
        int[][] dp = new int[M][bagweight + 1];

        for(int i = weight[0]; i <= bagweight; i++) {
            dp[0][i] = value[0];
        }
        for(int i = 1; i < M; i++) {
            for(int j = 1; j <= bagweight; j++) {
                if(weight[i] > j) {
                    dp[i][j] = dp[i - 1][j];
                }else {
                    dp[i][j] = Math.max(dp[i - 1][j - weight[i]] + value[i], dp[i - 1][j]);
                }
            }
        }
        System.out.println(dp[M - 1][bagweight]);
    }
}

背包问题 一维
题目链接:背包问题 一维
文档讲解︰代码随想录(programmercarl.com)
视频讲解︰背包问题 一维
日期:2024-10-09

想法:注意到二维数组的每一行的更新都是从上一行来的(都有个i - 1),那么只在同一行操作就能降低一维即递归变成:dp[j] = Math.max(dp[j - weight[i]] + value[i], dp[j])同样能达成目的。
Java代码如下:

import java.util.Scanner;

public class  Main {
    public static void main (String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        int bagweight = 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 j = 0; j < M; j++) {
            value[j] = scanner.nextInt();
        }
        int[] dp = new int[bagweight + 1];

        for(int i = 0; i < M; i++) {
            for(int j = bagweight; j >= weight[i]; j--) {
                dp[j] = Math.max(dp[j - weight[i]] + value[i], dp[j]);
            }
        }
        System.out.println(dp[bagweight]);
    }
}

总结:第一次写成了下面代码那样,对于背包容量依旧从小到大来,在背包只能放一个物品的时候没问题,但如果背包大小为2,物品0大小为1,我在设置背包容量为1的时候装了一次了即dp[1] = value[0]; 而到背包容量为2时计算dp[j - weight[i]] + value[i],这个dp[j - weight[i]] = dp[1],意思就是我会再装一次物品0来得到价值最大,这于物品放一次就不符合了,所以只能倒着遍历背包容量从j = bagweight开始,j >= weight[i]时就进入遍历公式,此时的dp[j - weight[i]] + value[i]依旧用的是之前没有变动过的数据,才能得到正确答案

import java.util.Scanner;

public class  Main {
    public static void main (String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        int bagweight = 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 j = 0; j < M; j++) {
            value[j] = scanner.nextInt();
        }
        int[] dp = new int[bagweight + 1];

        for(int i = 0; i < M; i++) {
            for(int j = 1; j <= bagweight; j++) {
                if(weight[i] > j) {
                    continue;
                }else {
                    dp[j] = Math.max(dp[j - weight[i]] + value[i], dp[j]);
                }
            }
        }
        System.out.println(dp[bagweight]);
    }
}

416. 分割等和子集
题目链接:416. 分割等和子集
文档讲解︰代码随想录(programmercarl.com)
视频讲解︰分割等和子集
日期:2024-10-09

想法:背包问题初遇还是挺难的,此题中背包容量为target = sum / 2,物品i大小为nums[i],价值也是nums[i],最后判断dp[target] == target,等于就能找到。
Java代码如下:

class Solution {
    public boolean canPartition(int[] nums) {
        if(nums == null || nums.length == 0) return false;
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        if(sum % 2 != 0) {
            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 >= nums[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
            }
        }
        if(dp[target] == target) {
            return true;
        }else return false;
    }
}

标签:背包,scanner,weight,int,随想录,value,416,dp
From: https://www.cnblogs.com/wowoioo/p/18455358

相关文章