【算法】----01背包问题(动态规划)

🌹作者:云小逸
📝个人主页:云小逸的主页
📝Github:云小逸的Github
🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天来之前,我们一起面朝大海,春暖花开!==🤟
👏专栏:C++👏 👏专栏:Java语言👏👏专栏:Linux学习👏
👏专栏:C语言初阶👏👏专栏:数据结构👏👏专栏:备战蓝桥杯👏


前言

今天我们来学习一下一个经典Dp问题----背包问题,这里将详细介绍背包问题的二维解法和一维解法。码字不易,请多多支持。在这里插入图片描述

——————————————————————————————

0-1背包问题

背包问题是一个经典的动态规划问题,其基本形式是:有一个容量为 V V V 的背包和 n n n 个物品,每个物品有一个体积 v i v_i vi 和一个价值 w i w_i wi。要求选择若干物品装入背包,使得装入背包中物品的总价值最大。其中每个物品只能选择装入一次

二维解法

状态定义

f ( i , j ) f(i,j) f(i,j) 表示前 i i i 个物品,体积不超过 j j j 的情况下可以获得的最大价值。

状态转移方程

对于第 i i i 个物品,有两种选择:

  1. 不放入背包,此时背包的最大价值为 f ( i − 1 , j ) f(i-1,j) f(i1,j)
  2. 放入背包,此时背包的最大价值为 f ( i − 1 , j − v i ) + w i f(i-1,j-v_i)+w_i f(i1,jvi)+wi

因此,状态转移方程为:

f ( i , j ) = max ⁡ { f ( i − 1 , j ) , f ( i − 1 , j − v i ) + w i } f(i,j)=\max\{f(i-1,j),f(i-1,j-v_i)+w_i\} f(i,j)=max{f(i1,j),f(i1,jvi)+wi}

详细讲解:

f数组:

在背包问题中,f数组一般表示状态转移方程中的“状态”,即 f ( i , j ) f(i,j) f(i,j)表示在前 i i i个物品中,背包容量为 j j j时的最大价值。也就是说, f ( i , j ) f(i,j) f(i,j)表示在当前背包容量为 j j j的情况下,前 i i i个物品能够获得的最大价值。在动态规划中,我们需要通过状态转移方程来不断更新 f ( i , j ) f(i,j) f(i,j)的值,最终得到背包问题的最优解。

f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);

这条语句是背包问题中的状态转移方程,表示在背包容量为 j 时,前 i 个物品能够获得的最大价值。

具体来说,f[i][j] 表示前 i 个物品,在背包容量为 j 时能够获得的最大价值。而根据背包问题的定义,第 i 个物品有两种选择,要么不装入背包,此时最大价值为 f[i-1][j];要么装入背包,此时最大价值为 f[i-1][j-v[i]] + w[i],其中 f[i-1][j-v[i]] 表示背包容量为 j-v[i] 时前 i-1 个物品的最大价值,w[i] 表示第 i 个物品的价值。因此,f[i][j] 就是这两种选择中的最大值。

代码实现

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int v[MAXN];    // 存储物品体积
int w[MAXN];    // 存储物品价值
int f[MAXN][MAXN];  // f[i][j]表示在背包容量为j的情况下,前i个物品的最大价值

int main() 
{
    int n, m;   
    cin >> n >> m;  // 输入物品数量和背包容量

    // 输入每个物品的体积和价值
    for(int i = 1; i <= n; i++) 
        cin >> v[i] >> w[i];

    // 动态规划求解
    for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= m; j++)
        {
            // 当前背包容量装不下第i个物品,则最大价值为前i-1个物品的最大价值
            f[i][j] = f[i - 1][j];

            // 当前背包容量能够装下第i个物品,需要对是否选择第i个物品进行决策
            if(j >= v[i])   
                f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
        }           

    cout << f[n][m] << endl;  // 输出最大价值

    return 0;
}

一维解法

状态定义

f ( j ) f(j) f(j) 表示体积不超过 j j j 的情况下可以获得的最大价值。

状态转移方程

对于第 i i i 个物品,有两种选择:

  1. 不放入背包,此时背包的最大价值为 f ( j ) f(j) f(j)
  2. 放入背包,此时背包的最大价值为 f ( j − v i ) + w i f(j-v_i)+w_i f(jvi)+wi

因此,状态转移方程为:

f ( j ) = max ⁡ { f ( j ) , f ( j − v i ) + w i } f(j)=\max\{f(j),f(j-v_i)+w_i\} f(j)=max{f(j),f(jvi)+wi}

详细解释:

int j = m; j >= v[i]; j–

这里的意思是从大到小枚举体积,因为在计算当前物品的最大价值时,需要用到之前物品的最大价值,而之前物品的最大价值可能已经被更新过,所以需要从大到小枚举体积,保证当前物品的体积不会影响之前物品的最大价值。同时,体积从大到小枚举也可以保证每个物品只被考虑一次,避免重复计算。

f[j] = max(f[j], f[j - v[i]] + w[i]);

在背包问题中,f[j]表示体积不超过j的情况下可以获得的最大价值。而f[j]的计算需要考虑两种情况:

  1. 不选第i个物品,此时f[j]的价值为f[j],即前i-1个物品的最大价值。
  2. 选第i个物品,此时f[j]的价值为f[j - v[i]] + w[i],即前i-1个物品在剩余容量为j - v[i]的情况下的最大价值加上第i个物品的价值w[i]。

因此,f[j]的值应该为这两种情况的最大值,即f[j] = max(f[j], f[j - v[i]] + w[i])。

代码实现

#include<bits/stdc++.h>

using namespace std;

const int MAXN = 1005;
int v[MAXN];    // 物品体积
int w[MAXN];    // 物品价值 
int f[MAXN];    // f[j]表示体积不超过j的情况下可以获得的最大价值

int main() 
{
    int n, m;   
    cin >> n >> m;  // n表示物品个数,m表示背包容量

    // 输入每个物品的体积和价值
    for(int i = 1; i <= n; i++) 
        cin >> v[i] >> w[i];

    // 01背包一维解法
    for(int i = 1; i <= n; i++) 
        for(int j = m; j >= v[i]; j--)
            f[j] = max(f[j], f[j - v[i]] + w[i]);

    cout << f[m] << endl;   // 输出最大价值

    return 0;
}

总结

二维解法和一维解法都是经典的背包问题解法,二者的时间复杂度都是 O ( n m ) O(nm) O(nm),但是一维解法的空间复杂度为 O ( m ) O(m) O(m),比二维解法的 O ( n m ) O(nm) O(nm) 更优秀。因此,在实际应用中,一维解法更为常用


最后

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1. 短期拼智力、中期拼毅力、长期拼体力。不要觉得自己落后了,用马拉松的心态,过自己的一生,你慢了一时一分,别焦虑。要看你我是否七八十岁,还有扛着锄头上山种橙子的那种勇气。

2.人间的美好,是3月的风,6月的雨,9月的云和12月的雪。

3.痛苦是对的。 痛苦源于对现状的不满,只有不满足于现状的人才会痛苦,痛苦才会深刻。痛苦的人,才有欲望去改造这一切。焦虑也是对的。焦虑是因为你想做得更好,说明你追求高,说明你眼界高,说明你知识多。痛苦和焦虑的人才是最真实的你我。

4.人生没有办法做到始终一帆风顺,也没有办法万事如意。但凡是你渴望的,都是你拿不到的;但凡是你乞求的,都是你实现不了的。 年轻人才会悔恨过去,能够坦然接受这一切的都是智者。

5.人生有一段路,一定要自己去走。 黎明前那一段天是最黑的, 但是只要再熬那么一会儿,天就亮了。 耐心就是智慧。 就连太阳光到达地球需要八分钟,你急什么呢? 那可是宇宙第一速度 。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

  • 13
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
01背包问题是一个经典的动态规划问题。它的目标是在给定背包容量的情况下,选择一些物品放入背包中,使得物品的总价值最大化,同时要保证背包的容量不超过限制。根据动态规划的原理,我们可以通过以下步骤来解决01背包问题: 1. 问题抽象化:将问题抽象为在给定背包容量和物品列表的情况下,选择一些物品放入背包中,使得物品的总价值最大化。 2. 建立模型:定义变量Vi表示第i个物品的价值,Wi表示第i个物品的体积。定义V(i,j)为当前背包容量j,前i个物品最佳组合对应的价值。 3. 寻找约束条件:约束条件是背包的容量不能超过限制,即对于每个物品i,有Wi <= j。 4. 判断是否满足最优性原理:最优性原理指的是最优解的子问题也是最优解。在01背包问题中,如果我们选择放入第i个物品,那么剩余背包容量就变为j-Wi,此时的最优解就是V(i-1,j-Wi)加上第i个物品的价值Vi。如果我们选择不放入第i个物品,那么最优解就是V(i-1,j)。因此,我们可以得到递推关系式:V(i,j) = max(V(i-1,j), V(i-1,j-Wi) + Vi)。 5. 找大问题与小问题的递推关系式:根据上述递推关系式,我们可以通过填表的方式来计算出所有的V(i,j)。 6. 填表:从i=1到n,j=0到背包容量的范围,依次计算V(i,j)的值。 7. 寻找解组成:通过填表的过程,我们可以得到最优解对应的V(n,C)的值,其中C为背包的容量。然后,我们可以根据V(i,j)的值逆推出最优解的组成方式。 综上所述,通过以上步骤,我们可以使用动态规划来解决01背包问题,并得到最优解以及解的组成。 #### 引用[.reference_title] - *1* *2* *3* [【动态规划01背包问题(通俗易懂,超基础讲解)](https://blog.csdn.net/qq_38410730/article/details/81667885)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云小逸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值