DAY42| 01.背包问题 二维、01.背包问题 一维、416.分割等和子集

详细布置

01.背包问题 二维
即dp[i][j]表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

在这里插入图片描述
在这里插入图片描述
dp[0][0]:物品0-0放进容量为0的背包的价值和是多少
dp[2][1]:物品0-2放进容量为1的背包的价值和是多少
dp[1][4]:物品0-1放进容量为4的背包的价值和是多少
dp[2][4]:物品0-2放进容量为4的背包的价值和是多少
dp [i - 1] [j] :物品0 — i-1放进容量为j的背包的价值和是多少
dp[i - 1][j - weight[i]]:物品0 — i-1放进容量为j的背包的价值和是多少(根据题意j从0-4)

不放物品i:由dp [i - 1] [j] 推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以被背包内的价值依然和前面相同。)

放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么(dp[i - 1][j - weight[i]] )+ value[i] ,就是背包放物品i得到的最大价值(- weight[i]之后再放肯定能放下物品i

所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

    /**
     * 动态规划获得结果
     * @param weight  物品的重量
     * @param value   物品的价值
     * @param bagSize 背包的容量
     */
    public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){

        // 创建dp数组
        int goods = weight.length;  // 获取物品的数量
        int[][] dp = new int[goods][bagSize + 1];//j下标为0表示包没有重量
        // 初始化dp数组
        // 创建数组后,其中默认的值就是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]) {
                    /**
                     * 当前背包的容量都没有当前物品i大的时候,是不放物品i的
                     * 那么前i-1个物品能放下的最大价值就是当前情况的最大价值
                     */
                    dp[i][j] = dp[i-1][j];
                } else {
                    /**
                     * 当前背包的容量可以放下物品i
                     * 那么此时分两种情况:
                     *    1、不放物品i:dp[i-1][j]
                     *    2、放物品i:dp[i-1][j-weight[i]] + value[i]
                     * 比较这两种情况下,哪种背包中物品的最大价值最大
                     */
                    dp[i][j] = Math.max(dp[i-1][j] , dp[i-1][j-weight[i]] + value[i]);
                }
            }
        }

        // 打印dp数组
        for (int i = 0; i < goods; i++) {
            for (int j = 0; j <= bagSize; j++) {
                System.out.print(dp[i][j] + "\t");
            }
            System.out.println("\n");
        }
    }
}

01.背包问题 一维
看视频去!!
https://www.bilibili.com/video/BV1BU4y177kY/?spm_id_from=333.788&vd_source=755fa867364448953d97aa99efa2ec41

416.分割等和子集
本题是 01背包的应用类题目
回溯算法核心 :每个元素取还是不取
在这里插入图片描述

class Solution {
    public boolean canPartition(int[] nums) {
        //先遍历数值
        //再遍历背包,倒序遍历 为了每个物品只放一次,正序的话用递推公式加会重复加进去
        //不能颠倒因为一维数组做了状态压缩,二维数组可以颠倒
        //这里重量和价值是相同的

        int n = nums.length;
        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 < n; i++) {
            for(int j = target; j >= nums[i]; j--) {
                //物品 i 的重量是 nums[i],其价值也是 nums[i]
                //相当于dp[i-1][j]去覆盖dp[i][j]
                //dp[j]:在包容量为j时不装新值的价值
                //dp[j-nums[i]] + nums[i]:装新值的价值 包容量减去物品容量所处的价值 加上新物品加上之后的价值
                dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);
            }
        }
        return dp[target] == target;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值