day41 背包问题

本文详细介绍了01背包问题的解决方案,运用动态规划方法,通过明确dp数组定义、初始化、递推公式、遍历顺序等步骤,以及一维和二维数组的比较,展示了如何计算在给定物品重量和价值条件下,背包容量为4时的最大价值。
摘要由CSDN通过智能技术生成

01背包问题

n种物品,每种物品只有1个,每种物品既有重量又有价值,背包最大重量为4,装满背包的最大价值是是多少?

物品weightvalue
物品0115
物品1320
物品2430
暴力解法

每个物品有2种状态(取与不取),使用回溯算法暴力搜索枚举  时间复杂度O(2^n)

二维数组

动态规划

动规五部曲

1.明确dp数组的定义

dp[i][j]  任取[0,i]之间的物品,放进容量为j的背包里面,背包的最大价值是dp[i][j]

2.dp数组初始化

初始化第一行第一列即可其他的根据递推公式,都可由第一行第一列推导而来,所以初始化成何值都没有关系

3.递推公式

当前背包状态取决于放不放物品i

不放物品i:dp[i-1][j]       放物品i的最大价值: dp[i-1][j-weight[i]]+value[i]

dp[i][j] = dp[i-1][j] + dp[i-1][j-weight[i]] + value[i]

4.遍历顺序

5.打印dp数组

代码 

遍历时,关于背包容量j与当前背包重量weight[i]一定要分类讨论

#include<bits/stdc++.h>

using namespace std;
int main(){
    int M,N;
    cin>>M>>N;//材料
    
    std::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];
    }
    //01背包问题
    //1 定义dp数组
    vector<vector<int>> dp(weight.size(),vector<int>(N+1,0));//0还要算一次背包容量
    //2 初始化dp数组
    //背包容量为0时 初始化为0
    for(int i=0;i<weight.size();i++){
        dp[i][0] = 0;
    }

    //放第一个物品0时
    //若背包容量小于物品0的重量,则初始化为0
    //若背包容量大于物品0的重量,则初始化为物品0的重量
    //当j=0,即背包容量为0的情况已经讨论过了,所以这里直接取j=1
    for(int j=1;j<=N;j++){
        if(j<weight[0]) dp[0][j] = 0;
        else dp[0][j] = value[0];
    }
    //3 遍历顺序
    //先遍历物品,后遍历背包
    for(int i=1;i<weight.size();i++){  //第一行已经初始化
        for(int j=1;j<=N;j++){//第一列已经初始化了
        if(j<weight[i]) dp[i][j] = dp[i-1][j];
        //4 递推公式
        else dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i]);
        //cout<<dp[i][j]<<endl;
        }
    }
    cout<<dp[M-1][N]<<endl;
    
    return 0;
}

滚动数组(一维数组)

动态规划

动规五部曲

1)明确dp数组及下标i的含义

当前层是由上一层拷贝过来的,

dp[j] 背包容量为j的背包的最大价值是dp[j]

2)dp数组初始化

背包容量为0时,dp[0]=0

背包容量不为0时,根据递推公式,dp[j]=max(dp[j],dp[j-weight[i]]+value[i]),将dp[j]初始化为非负整数的最小值0,这样才不会掩盖递推公式求得的max的结果,所以dp[j]=0

3)递推公式

dp[j] = max(dp[j],dp[j-weight[i]]+value[i])

4)遍历顺序

!!!一定要先遍历物品,后倒序遍历背包!!!

反(先遍历背包,后遍历物品)

5)打印dp数组

!!!二维dp数组是每层完全隔开的,当前层的每一个值不受干扰,

一维dp数组每次重复利用,当前层的数值和当前层的旧值会产生冲突  所以遍历顺序不同!!!

代码

#include<vector>
#include<iostream>

using namespace std;
int main(){
    int M,N;
    cin>>M>>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];
    }
    //01背包问题
    //1 定义dp数组 //2 初始化dp数组
    vector<int> dp(N+1,0);

    //3 遍历顺序
    //先遍历物品,后倒序遍历背包
    for(int i=0;i<weight.size();i++){ 
        for(int j=N;j>=weight[i];j--){
        //4 递推公式
        dp[j] = max(dp[j], dp[j-weight[i]]+value[i]);
        }
    }
    cout<<dp[N]<<endl;
    
    return 0;
}

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值