首页 > 其他分享 >(41/60)0-1背包(二维数组、一维数组)、分割等和子集

(41/60)0-1背包(二维数组、一维数组)、分割等和子集

时间:2024-03-21 23:58:14浏览次数:24  
标签:背包 weight nums int sum 41 60 数组 dp

有点抽象

0-1背包

卡码网:携带研究材料(第六期模拟笔试)

动态规划

思路

二维:

  1. 意义:0~i物品内,放进容量为j的背包,最大价值为dp[i][j]
  2. 递推:dp[i][j] = max(dp[i-1][j-weight[i],dp[i-1][j])
  3. 初始化:第一列为0,第一行j>=weight[0]时赋值为value[0]
  4. 遍历:先背包再物品/先物品再背包 均可

(每层元素都由上一层推出。正上、左上

一维:

  1. 意义:容量为j的背包最大价值为dp[j]
  2. 递推:dp[j] = max(dp[j],dp[j-weight[i]] + value[i]) 取、不取
  3. 初始化:初始化为0
  4. 遍历:先物品再背包,倒序

(每层元素由当前层推出。自身、左。每层元素既是本层,也是上层。每轮背包遍历,更新前的值表示上层,更新后的值为当前层)

复杂度分析

时间复杂度:O(N^2)。

空间复杂度:二维数组O(N^2),一维数组O(N)。

代码实现

二维数组版:

#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;

/*
意义:0~i物品内,放进容量为j的背包,最大价值为dp[i][j]
递推:dp[i][j] = max(dp[i-1][j-weight[i],dp[i-1][])
初始化:第一列为0,第一行j>=weight[0]时赋值为value[0]
遍历:先背包再物品/先物品再背包 均可
*/

int main(){
    int M = 0;  // item types
    int N = 0;  // capacity
    cin>>M;
    cin>>N;
    vector<int> weight(M,0);
    vector<int> value(M,0);
    for(int i = 0;i < M;i++){
        cin>>weight[i];
    }
    for(int i = 0;i < M;i++){
        cin>>value[i];
    }
    
    vector<vector<int>> dp(M,vector<int>(N+1,0));
    for(int j = 1;j <= N;j++){
        if(j >= weight[0]) dp[0][j] = value[0];
    }
    
    for(int i = 1;i < M;i++){
        for(int j = 1;j <= N;j++){
            if(j >= weight[i]){ // 如果
                dp[i][j] = max( dp[i-1][j],dp[i-1][j-weight[i]] + value[i] );
            }else{
                dp[i][j] = dp[i-1][j];
            }
            
        }
    }
    cout<<dp[M-1][N]<<endl;
    return 0;
}

一维数组版:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

/*
意义:容量为j的背包最大价值为dp[j]
递推:dp[j] = max(dp[j],dp[j-weight[i]] + value[i]) 取、不取
初始化:初始化为0
遍历:先物品再背包,倒序
*/

int main(){
    int M = 0;  // count of types
    int N = 0;  // capacity
    cin>>M;
    cin>>N;
    vector<int> weight(M,0);
    vector<int> value(M,0);
    for(int i = 0;i < M;i++){
        cin>>weight[i];
    }
    for(int i = 0;i < M;i++){
        cin>>value[i];
    }
    
    vector<int> dp(N+1,0);
    for(int i = 0;i < M;i++){	// 先遍历物品
        for(int j = N;j >= weight[i];j--){	// 再遍历背包(倒序)
            dp[j] = max(dp[j],dp[j-weight[i]] + value[i]);
        }
    }
    
    cout<<dp[N];
    
    
    return 0;
}

分割等和子集

leetcode:416. 分割等和子集

动态规划

思路

容量和价值都是nums[i]

  1. 意义:容量为j的背包最大价值为dp[j] if(dp[sum/2] == sum/2) return true;
  2. 容量sum/2的背包装的最大价值为sum/2
  3. 初始化:为0
  4. 遍历:先物品再背包,倒序

复杂度分析

时间复杂度:O(N^2)。

空间复杂度:O(N)。

代码实现

C++:

class Solution {
public:
/*
可看成0-1背包问题,weight和value都是数字大小
意义:容量为j的背包最大价值为dp[j]   if(dp[sum/2] == sum/2) return true; 
容量sum/2的背包装的最大价值为sum/2
初始化:为0
遍历:先物品再背包,倒序

*/
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for(int num : nums) sum += num;
        if(sum%2 == 1) return false;    // 总和为奇数,不可能对半分
        int n = nums.size();
        vector<int> dp(sum/2 + 1,0);
        for(int i = 0;i < n;i++){
            for(int j = sum/2;j >= nums[i];j--){
                dp[j] = max(dp[j],dp[j - nums[i]] + nums[i]);
            }
        }
        if(dp[sum/2] == sum/2) return true;
        else return false;
    }
};

TS:

/**
意义:容量为j的背包,装的最大价值是dp[j] (weight[]和value[]都是nums[])
递推:dp[j] = max(dp[j],dp[j - nums[i]] + nums[i])
初始化:置为0
遍历:先物品再背包,倒序
 */

function canPartition(nums: number[]): boolean {
    let sum = 0;
    nums.forEach((item) => sum += item);
    if(sum%2 == 1) return false;
    let dp = new Array(sum/2 + 1).fill(0);
    for(let i = 0;i < nums.length;i++){
        for(let j = sum/2;j >= nums[i];j--){
            dp[j] = Math.max(dp[j],dp[j - nums[i]] + nums[i]);
        }
    }

    if(dp[sum/2] === sum/2) return true;
    else return false;
};

标签:背包,weight,nums,int,sum,41,60,数组,dp
From: https://www.cnblogs.com/tazdingo/p/18088499

相关文章

  • (46/60)单词拆分、多重背包
    day46单词拆分leetcode:139.单词拆分动态规划代码实现/*意义:长度为j的字符串能否被dict里的单词拼出为dp[j]递推:if(dp[j]&&j~i子串在dict里)dp[i]=true;初始化:dp[0]=true无意义,只是滚雪球起点;其余为false遍历:对顺序有要求,排列数,先背包后物品;可重复取,正序*/......
  • (45/60)爬楼梯进阶、零钱兑换、完全平方数
    day45爬楼梯进阶卡码网:爬楼梯(第八期模拟笔试)动态规划代码实现/*总和为j总共有dp[j]种方法(可重复选取、排列)dp[j]+=dp[j-nums[i]dp[0]=1;其余为0先背包再物品,正序*/#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intmain(){......
  • (44/60)完全背包、零钱兑换Ⅱ、组合总和Ⅳ
    day44完全背包卡码网:携带研究材料(第七期模拟笔试)动态规划思路完全背包,物品可以无限次取,正序遍历。复杂度分析时间复杂度:O(N^2)。空间复杂度:O(N)。代码实现#include<iostream>#include<algorithm>#include<vector>usingnamespacestd;/*给j的容量可重复选择的最......
  • (51/60)买卖股票的最佳时机含冷冻期、买卖股票的最佳时机含手续费
    day51买卖股票的最佳时期含冷冻期leetcode:309.买卖股票的最佳时机含冷冻期动态规划代码实现/*意义:下标为i时各种情况的收益dp[i][0]持有dp[i][1]当天卖出dp[i][2]之前不持有递推:dp[i][0]=max(dp[i-1][0],dp[i-1][2]-prices[i]);//之前持有、之前不持有且当......
  • (50/60)买卖股票的最佳时机Ⅲ、买卖股票的最佳时机Ⅳ
    day50买卖股票的最佳时机Ⅲleetcode:123.买卖股票的最佳时机III动态规划代码实现/*意义:下标为i时,不同状态收益为dp[i][0]未持有dp[i][1]第一次持有dp[i][2]第一次未持有dp[i][3]第二次持有dp[i][4]第二次未持有递推:dp[i][0]=dp[i-1][0];之前未持有dp[i]......
  • (48/60)买卖股票的最佳时机、买卖股票的最佳时机Ⅱ
    day48买卖股票的最佳时机leetcode:121.买卖股票的最佳时机动态规划代码实现/*意义:dp[i][0]下标为i天持有股票的最大收益;dp[i][1]下标为i天不持股的最大收益递推:之前买入、当天买入:dp[i][0]=max(dp[i-1][0],-prices[i]);之前卖出、当天卖出:dp[i][1]=max(dp[i-1][1],......
  • (47/60)打家劫舍、打家劫舍Ⅱ、打家劫舍Ⅲ
    day47打家劫舍leetcode:198.打家劫舍动态规划代码实现/*偷到下标为i的最大金额数为dp[i]偷i、不偷i:dp[i]=max(dp[i-2]+nums[i],dp[i-1]);dp[0]=nums[0];dp[1]=max(nums[0],nums[1]);正序遍历*/classSolution{public:introb(vector<int>&nums){......
  • 循环控制:(第10题)与闰年相关的问题,涉及数组,函数的知识
    #include<stdio.h>intis_leap_year(intyear){ if((year%4==0&&year%100!=0)||year%400==0) return1; else return0;}intgap_years(intyear){ inti=1990; intsum=0; intgap_years=0; if(year==1990) retur......
  • 非有序数组也能二分? —— 红蓝染色法续篇(Leetcode 162.寻找峰值)
    1.写在前面本文为个人学习总结,参考:B站Up:灵茶山艾府参考视频链接:https://www.bilibili.com/video/BV1QK411d76w/2.题目我们来看一下下面这道题:峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在......
  • 科技赋能生活:KTH1601让垃圾桶“懂”你的需求
    在现代社会,科技的快速发展不仅仅改变了我们的生活方式,甚至连日常生活中的垃圾桶也变得“智能”起来。高性能、低功耗霍尔开关传感器KTH1601,正是让智能垃圾桶能够自动感应、自动开关的关键所在。它是由昆泰芯微电子科技有限公司研发的一款全极磁场检测传感器,具备非常低的功耗......