Loading [MathJax]/jax/input/TeX/jax.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >DP:背包问题----0/1背包问题

DP:背包问题----0/1背包问题

作者头像
用户11305458
发布于 2024-10-09 09:10:58
发布于 2024-10-09 09:10:58
4060
举报
文章被收录于专栏:学习学习

💗背包问题

背包问题(Knapsack Problem)是一类经典的组合优化问题,在计算机科学和数学中有广泛应用。其基本问题是:

  • 输入:给定一个容量为
W

的背包和

n

个物品,每个物品

i

有一个重量

wi

和一个价值

vi

  • 目标:选择若干个物品放入背包,使得总重量不超过背包的容量
W

,并且总价值最大化。

💛背包问题的变体

  1. 0/1 背包问题:每个物品只能选择一次,即要么选中(1)要么不选(0)。
  2. 分数背包问题:每个物品可以分割,即可以选择物品的一部分。
  3. 多重背包问题:每个物品有多个副本,可以选择多个相同的物品。
  4. 多维背包问题:背包有多个限制条件,例如容量和体积等。

🧡0/1 背包问题的数学定义

目标函数:

maximizeni=1cixi

其中,

n

表示物品的数量,

ci

表示物品

i

的价值。

约束条件:

ni=1wixiC

其中,

wi

表示物品

i

的重量,

C

表示背包的容量。

其它约束条件:

xi{0,1}
i=1,2,3,,n

其中,

xi

表示物品

i

是否被选中。

💚解决背包问题的方法

解决背包问题的方法有很多,包括动态规划、分支定界法、贪心算法(适用于分数背包问题)以及各种近似算法和启发式算法等。

💙例子

假设有一个背包容量为 50 的背包,有以下物品:

物品

重量

价值

1

10

60

2

20

100

3

30

120

目标是选择物品使得总重量不超过 50 且总价值最大化。在这个例子中,最佳选择是选取物品 2 和物品 3,总重量为 50,总价值为 220。

💗解决背包问题的一般步骤?

背包问题是一个经典的优化问题,可以通过动态规划算法来解决。下面是解决背包问题的一般步骤:

  1. 确定问题的约束条件:背包的容量限制和物品的重量和价值。
  2. 定义状态:将问题拆解为多个子问题,定义状态为背包的容量和可选择的物品。
  3. 定义状态转移方程:根据子问题的定义,确定状态之间的关系。例如,对于背包问题,可以定义状态转移方程为f(i,j),表示在前i个物品中选择,背包容量为j时,可以获得的最大价值。则可以得到状态转移方程:f(i,j) = max(f(i-1,j), f(i-1,j-w[i])+v[i]),其中w[i]和v[i]分别表示第i个物品的重量和价值。
  4. 确定初始条件:确定边界条件,即背包容量为0时,价值为0。
  5. 通过动态规划算法计算最优解:根据状态转移方程和初始条件,利用循环或递归的方式计算最优解。
  6. 回溯最优解:根据计算得到的最优解,可以通过回溯的方式确定选择了哪些物品放入背包中,从而得到最终的解。

需要注意的是,背包问题的解决方法还包括贪心算法、分支界限算法等。具体选择哪种方法取决于问题的约束条件和需要优化的目标。

💗例题

题目链接 题目:

样例输出和输入:

这道题并不是leetcode的那种接口的模式,而是ACM模式,我们需要进行完整的输入和输出,我们先分析第一个样例:

0

1

2

3

容量

2

4

1

价值

10

5

4

第一个问题是给定一个背包容量,求出当背包的容量不用装满时的最大价值,意思就是我们选出的物品的总的容量可以小于背包的容量,也可以等于背包的容量,这时,我们可以第一个物品和三个物品的价值是最大的。 总价值为14, 第二个问题是我们必须将 背包容量给塞满,求塞满的状态的物品的最大价值,这种情况下有可能是没有结果的,因为无法选出能将背包塞满的组合 ,所以这时候就输出零。但是这个例子是可以输出结果的,塞满的情况应该是第二个物品和第三个物品,总价值是9,所以最后输出14和9。

算法原理: 状态表示:dp[i][j]-----表示选到第i个位置时的所有选法中的不超过总容积j的最大价值。 状态转移方程:

这是不把背包填满的情况下的状态转移方程,还有一个问题就是需要将背包填满。

所以这里如果要用到前一个状态的话,应该判断一下前一个状态是否是-1,如果前一个状态是-1的话,就表示这种情况根本不存在 ,所以不能选择这种状态

初始化:第一个问题的初始化只需要将dp表初始化为0,第二个问题的初始化上面已经讨论过了。 填表顺序:也是按照从左上角到右下角,依次填表。 返回值:返回dp[n][V] 代码展示:

代码语言:javascript
AI代码解释
复制
#include <cstring>
#include <iostream>
#include<string>
using namespace std;

//数据范围
const int N = 1010;
//n个数据,V为背包的总容量,v表示单个物品的所占容积,w表示单个物品所含的价值
int n, V, v[N], w[N];
//i表示第i个位置,j表示总的容积
int dp[N][N];

int main()
{
    //输入总数据,和总容积
    cin >> n >> V;
    for (int i = 1;i <= n;i++)
    {
        cin >> v[i] >> w[i];
    }
    //解决第一问
    for (int i = 1;i <= n;i++)
    {
        //j表示容量
        for (int j = 1;j <= V;j++)
        {
            //不选的情况
            dp[i][j] = dp[i - 1][j];
            //如果能选,则和之前不选的情况求一个max
            if (j >= v[i])dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
        }
    }
    //输出最后一个dp状态
    cout << dp[n][V] << endl;
    //重置dp表,将表中数据重置为0
    memset(dp, 0, sizeof dp);
    //单独初始化第一排的后面的位置,因为如果没有任何物品根本不可能有价值,所以初始化为-1
    for (int i = 1;i <= V;i++)
    {
        //初始化不存在dp的位置
        dp[0][i] = -1;
    }
    for (int i = 1;i <= n;i++)
    {
        //j表示容量
        for (int j = 1;j <= V;j++)
        {
            //可以不选
            dp[i][j] = dp[i - 1][j];
            //如果要选择当前位置的话需要考虑前一个状态是否是-1,选不到的情况 
            if (j >= v[i] && dp[i - 1][j - v[i]] != -1)
                dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
        }
    }
    //如果不存在选满的情况,直接返回0,否则返回dp[n][V]位置的值
    cout << (dp[n][V] == -1 ? 0 : dp[n][V]) << endl;
    return 0;
}

代码优化: 可以利用滚动数组进行优化:

代码语言:javascript
AI代码解释
复制
#include <cstring>
#include <iostream>
#include<string>
using namespace std;

//数据范围
const int N = 1010;
//n个数据,V为背包的总容量,v表示单个物品的所占容积,w表示单个物品所含的价值
int n, V, v[N], w[N];
//i表示第i个位置,j表示总的容积
int dp[N];

int main()
{
    //输入总数据,和总容积
    cin >> n >> V;
    for (int i = 1;i <= n;i++)
        cin >> v[i] >> w[i];
    //解决第一问
    for (int i = 1;i <= n;i++)
        //j表示容量
        for (int j = V;j >= v[i];j--)//修改遍历顺序
            //如果能选,则和之前不选的情况求一个max
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
    //输出最后一个dp状态
    cout << dp[V] << endl;
    //重置dp表,将表中数据重置为0
    memset(dp, 0, sizeof dp);
    //单独初始化第一排的后面的位置,因为如果没有任何物品根本不可能有价值,所以初始化为-1
    for (int i = 1;i <= V;i++)
        //初始化不存在dp的位置
        dp[i] = -1;
    for (int i = 1;i <= n;i++)
        //j表示容量
        for (int j = V;j >= v[i];j--)//修改遍历顺序
            //如果能选,则和之前不选的情况求一个max
            if(dp[j-v[i]]!=-1)
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
    //如果不存在选满的情况,直接返回0,否则返回dp[n][V]位置的值
    cout << (dp[V] == -1 ? 0 : dp[V]) << endl;
    return 0;
}

运行结果:

💗总结

通过对0/1背包问题的分析和动态规划解法的详细讲解,我们可以看到这种经典问题在算法设计中的重要性。0/1背包问题不仅是许多实际应用的基础,也是理解和掌握动态规划思想的一个重要实例。

在解决0/1背包问题时,关键在于构建状态转移方程并合理使用空间和时间资源。通过递归和迭代的方法,我们能更好地理解背包问题的解法,优化算法效率,并提升解决复杂问题的能力。

希望这篇博客能帮助你理解0/1背包问题的基本原理和解法,同时激发你对动态规划和算法设计的进一步兴趣和探索。未来的学习中,不妨尝试更多的变种背包问题和动态规划问题,以不断提升自己的算法技能和编程水平。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
动态规划--0,1背包问题(再也不怕类似背包问题了)
这种类型问题三大要素:总重量、每件物品重量、每件物品价值,问最终能够塞进背包中的价值最大是多少?应该怎么选择物品?
西西嘛呦
2020/08/26
5040
【dp】背包问题
背包问题是⼀种组合优化的问题。问题可以描述为:给定⼀组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。
YoungMLet
2024/03/01
2170
【dp】背包问题
常见动态规划类型--案例详解
动态规划的核心思想是将原问题拆解成子问题,并通过解决子问题来求解原问题。为了避免重复计算,动态规划会将子问题的解进行存储,在需要的时候直接获取,从而提高效率。
刺槐儿
2023/11/17
8250
01-背包问题及相关应用
有 N 件物品和一个容量为 C 的背包。第 i 件物品的重量是 w[i],价值是 v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。如:
echobingo
2019/06/11
7280
01-背包问题及相关应用
0/1背包问题总结
假设有一个背包,它能够承载一定的重量。现在有一组物品,每个物品有各自的重量和价值。我们的目标是在不超过背包承载重量的前提下,选择一些物品放入背包中,使得背包中物品的总价值最大化。
用户11305458
2024/10/09
2610
0/1背包问题总结
背包九讲——背包问题求具体方案
上一篇说了一下背包问题求方案数,下面进行深化一点就是求具体方案了。同上一篇这些问题都是在01背包、多重背包、完全背包基础上演化来的,求具体方案问题会问你一种具体方案(编号序列的字典序最小)或者打印所有具体方案,一般的问题都是问你第一种。若为第二种问法,建议使用C语言的printf进行打印,因为打印所有具体方案,当数据量很大时会有很多输出,使用printf会比cout快一点。根据问题的具体类型,常见的背包问题包括:
摆烂小白敲代码
2024/11/24
2200
背包九讲——背包问题求具体方案
【动态规划/背包问题】那就从 0-1 背包问题开始讲起吧 ...
如果你还没看过,我十分建议你抽时间去学习一下。因为 路径问题 里教到的「经验解法」和「技巧解法」将会贯穿我们之后的所有「动态规划专题」系列。
宫水三叶的刷题日记
2021/04/08
1.1K0
背包九讲——完全背包问题
完全背包问题呢,见名知意,就是所谓的物品无限多,选也选不完的那种,是多重背包的promax版本。完全背包问题是背包问题的一种变体,与0/1背包问题有所不同。在完全背包问题中,每种物品的数量是无限的,可以选择任意数量的某一种物品放入背包中。问题的描述如下: 给定一个背包容量为m,有n种物品,每种物品有重量v[i]和价值w[i],且数量无限。目标是选择物品放入背包,使得它们的总重量不超过背包容量,并且总价值最大。 与0/1背包问题相比,完全背包问题的状态转移方程有所不同,因为每种物品可以选择多次。 解决完全背包问题的方法与0/1背包问题类似,可以使用动态规划、贪心算法等。常见的动态规划方法包括自底向上的迭代和自顶向下的递归+记忆化搜索。
摆烂小白敲代码
2024/10/22
3090
背包九讲——完全背包问题
背包九讲学习笔记
本文内容基本涵盖了 dd_engi 的背包九讲,在此基础上加上了自己的理解和代码实现
EmoryHuang
2022/10/28
4920
背包九讲学习笔记
背包九讲——多重背包问题
多重背包问题是背包问题的一种扩展,与0/1背包问题和分数背包问题有些不同。在多重背包问题中,每种物品都有限定的数量,不再是仅有一个,而是有多个。问题的描述如下: 给定一个背包容量为C,有n种物品,每种物品有重量w[i]、价值v[i]和数量s[i]。目标是选择物品放入背包,使得它们的总重量不超过背包容量,并且总价值最大。 这个问题在一些应用中更为真实,例如购物时某种商品有多件可供选择。解决多重背包问题的方法通常是在0/1背包问题的基础上进行一些调整。
摆烂小白敲代码
2024/10/19
4600
背包九讲——多重背包问题
DP:完全背包问题
动态规划(DP)是算法中的重要技术,背包问题则是其中的经典问题之一。本篇博客将介绍完全背包问题及其解决方案。
用户11305458
2024/10/09
3170
DP:完全背包问题
背包九讲—-整理+例题[通俗易懂]
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
全栈程序员站长
2022/08/03
1.2K0
背包九讲—-整理+例题[通俗易懂]
【愚公系列】2023年12月 五大常用算法(三)-动态规划算法
动态规划算法的基本思想是将原问题分解为若干个子问题,并先求解子问题,再根据子问题的解得到原问题的解。这种方法的优点在于避免了重复计算,从而提高了算法的效率。
愚公搬代码
2023/12/14
3791
背包九讲——混合背包问题
混合背包问题是一类组合优化问题,它结合了01背包问题、完全背包问题和多重背包问题的特点。在混合背包问题中,有多种物品和一个固定容量的背包,每种物品有自己的重量和价值,并且每种物品可能有使用次数的限制。
摆烂小白敲代码
2024/11/24
2990
背包九讲——混合背包问题
文心一言 VS 讯飞星火 VS chatgpt (215)-- 算法导论16.2 2题
0-1 背包问题是一个典型的动态规划问题,其目标是在给定的重量限制下最大化背包中物品的总价值。每个物品可以选择放入背包或不放入背包(0-1表示),并且每种物品只有一个。
福大大架构师每日一题
2024/03/18
1540
文心一言 VS 讯飞星火 VS chatgpt (215)-- 算法导论16.2 2题
深度讲解背包问题:面试中每五道动态规划就有一道是背包模型 ...
在使用一维数组解决 0-1 背包问题的基础上,讲解如何解决完全背包、多重背包、分组背包、背包具体方案 和 有依赖的背包问题 ...
宫水三叶的刷题日记
2021/02/20
1.9K0
Python 算法基础篇:背包问题的动态规划解法
背包问题是计算机科学中一个重要的组合优化问题,动态规划是解决该问题的高效算法技术。本篇博客将重点介绍背包问题的动态规划解法,包括状态定义、状态转移方程、边界条件和状态转移过程,并通过实例代码演示动态规划算法的实现,每行代码都配有详细的注释。
小蓝枣
2023/07/25
8910
浅谈完全背包问题
完全背包问题呢,见名知意,就是所谓的物品无限多,选也选不完的那种,是多重背包的promax版本。完全背包问题是背包问题的一种变体,与0/1背包问题有所不同。在完全背包问题中,每种物品的数量是无限的,可以选择任意数量的某一种物品放入背包中。问题的描述如下: 给定一个背包容量为m,有n种物品,每种物品有重量v[i]和价值w[i],且数量无限。目标是选择物品放入背包,使得它们的总重量不超过背包容量,并且总价值最大。 与0/1背包问题相比,完全背包问题的状态转移方程有所不同,因为每种物品可以选择多次。 解决完全背包问题的方法与0/1背包问题类似,可以使用动态规划、贪心算法等。常见的动态规划方法包括自底向上的迭代和自顶向下的递归+记忆化搜索。
摆烂小白敲代码
2024/09/23
1830
浅谈完全背包问题
【算法】DP背包问题(C/C++)
个人主页:摆烂小白敲代码 创作领域:算法、C/C++ 持续更新算法领域的文章,让博主在您的算法之路上祝您一臂之力 欢迎各位大佬莅临我的博客,您的关注、点赞、收藏、评论是我持续创作最大的动力
摆烂小白敲代码
2024/09/23
2360
【算法】DP背包问题(C/C++)
文心一言 VS 讯飞星火 VS chatgpt (216)-- 算法导论16.2 3题
在0-1背包问题中,如果商品的重量递增序与价值递减序完全一样,那么我们可以利用这个特性设计一种高效的算法。对于这种情况,我们可以从重量最轻、价值最高的商品开始考虑,依次判断是否可以放入背包中。这种策略是基于一个直观的观察:更重的物品往往价值更低,所以我们应该优先考虑轻且价值高的物品。
福大大架构师每日一题
2024/03/18
1930
文心一言 VS 讯飞星火 VS chatgpt (216)-- 算法导论16.2 3题
推荐阅读
相关推荐
动态规划--0,1背包问题(再也不怕类似背包问题了)
更多 >
交个朋友
加入腾讯云官网粉丝站
双11活动抢先看 更有社群专属礼券掉落
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档