算法day42|背包问题

背包问题分为:01背包,完全背包,多种背包

  • 01背包指的是有n种物品,每种物品只能取一个
  • 完全背包指的是有n种物品,每种物品可以取无限个
  • 多种背包指的是有n种物品,每种物品的数量各不相同

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

01背包问题 二维

动态规划五部曲:

  • 初始化

首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。如图:

 最后

  • 遍历顺序

遍历顺序可以先遍历物品,也可以先遍历书包重量

  • dp数组的定义以及含义

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

  • 递归公式

dp[i][j]分为两种情况,一种是取i这个物品,一种是不取i这个物品

取i这个物品:

dp[i-1][j-weight[i]]+value[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的价值),就是背包放物品i得到的最大价值

不取i这个物品:dp[i-1][j]

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

然后两个取其中的最大值

  • 打印dp数组

代码随想录

视频讲解:带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili

01背包问题 一维

滚动数组的想法,不断的取更新数组

代码随想录

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

面试问题:

二维数组实现后,遍历顺序可以调换吗?

一维数组实现后,遍历顺序可以调换吗?for循环为什么是从后往前,而不是从前往后

416. 分割等和子集

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        target = sum(nums)
        #如果nums中的数无法平均拆成两半,那么返回false
        if target % 2 == 1: return False
        target //= 2
        #定义dp数组,并且确定其含义,dp[j]意味着取j容量的最大价值,这里价值和容量相等
        dp = [0] *10001
        #遍历物体
        for i in range(len(nums)):
        #遍历容量,容量要从后向前遍历才不会取重复物体
            for j in range(target, nums[i] - 1, -1):
                #分两种情况,取i/不取i,不取i的话,就是dp[j]。
                #取i物品的话,dp[j-nums[i]] j容量需要减去物品i的容量,再加上它的价值
                dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
        #最后背包容量是target,dp[target]是装满背包后的容量
        if target == dp[target]:
            return True
        else:
            return False

时间超时了,我也不知道为什么

本题是 01背包的应用类题目

代码随想录

视频讲解:动态规划之背包问题,这个包能装满吗?| LeetCode:416.分割等和子集_哔哩哔哩_bilibili

 

 二刷(未ac)

var canPartition = function(nums) {
    // 背包容量看一下是否能划分为相等的两个,或者是整数,如果不能整除绝对是false
    let summ = nums.reduce((a,b)=>a+b)
    if(summ % 2 !== 0) return false
    let weight = summ / 2
    // 滚动数组
    // 转化题意,查询背包容量为11的背包是否能被装满。就是看dp[j](dp[11]等于weight吗)
    let dp = new Array(weight+1).fill(0)
    // 初始化,dp[j]的最大价值为0
    // 背包总价值为weight
    // dp[j] 代表的是j容量背包,所装的最大价值为dp[j]
    for(let i = 0;i<nums.length;i++){ // 遍历物品
        for(let j = weight;j>=nums[i];j--){  // 遍历背包容量
            // 放物品i和不妨物品i
            dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i])
        }
    }
    console.log(dp)
    if(dp[weight] === weight){
        return true
    }else{
        return false
    }
    
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值