动态规划:0-1背包、完全背包问题 | 详细原理解释 | 代码及优化(C++)

这篇具有很好参考价值的文章主要介绍了动态规划:0-1背包、完全背包问题 | 详细原理解释 | 代码及优化(C++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

01背包

问题描述:

简单描述就是:

解析:

递推公式:

dp数组的初始化:

遍历顺序:

图解:

实现代码:

dp数组初始化:

遍历:

优化:

原理:

递推公式:

遍历顺序:

实现代码:

初始化:

遍历:

完全背包

问题描述:

解析:

实现代码:


01背包

问题描述:

        01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。如果不选择将其放入背包中,则不需要处理。如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。(来源:百度百科)

简单描述就是:

        有N件物品和一个容量为M的背包。第 i 件物品的体积(也可以是重量等)是w[ i ],价值是v[ i ]。求解将哪些物品装入背包可使价值总和最大。

解析:

递推公式:

        如果没接触过背包问题的话,应该首先会想到的是暴力写法,也就是回溯算法,把所有的情况都找出来,然后通过不断的比较和更新求出最大价值,显然这种方法的需要的时间是很长的,时间复杂度是2的n次方。

        所以我们就要用动态规划,最重要的就是理解dp数组的含义,若是dp[ i ][ j ]数组不理解,后面的就更不可能理解了,dp[ i ][ j ]数组的含义就是在0 ~ i的物品中选取放入 j 容量的背包得到的最大价值。注意这里选取不是全都放进去的意思,是选择其中的任意几个放进去,一个物品是有两种状态的,已放入和未放入,就是对于前 i 个物品进行放入或未放入的选择后得到的最大价值。

        现在我们对于前 i 个物品进行选择求出最大价值,一个物品有两个状态,写出递推公式:

i 不放入:dp[ i ][ j ] = dp[ i - 1 ][ j ]

i 确定放入:dp[ i ][ j ] = dp[ i - 1 ][ j - w[ i ] ] + v[ i ]

求最大:max(dp[ i - 1 ][ j ], dp[ i - 1 ][ j - w[ i ] ] + v[ i ])

        不放入的递推公式好理解,就是已经确定第 i 件不放入了,那我们的最大价值就等于在前 i - 1的中选取放入 j 容量背包的最大价值。

        确定放入的递推公式不好理解,因为我们这里已经确定第 i 件放入,那就说明 i 一定会放入,我们要把背包留出第 i 件的空间,所有我们就对于前 i - 1 件选取放入 j - w[ i ] 的容量中,这里减去的 w[ i ] 就是为第 i 件留出的空间,然后加上第 i 件的价值,就求出了确定放入的最大价值。

        然后我们在不放入放入之中获得他们的最大值就得到了dp[ i ][ j ],下面给出完整递推公式:

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

dp数组的初始化:

        通过递推公式,我们可以发现dp[ i ][ j ]在二维数组中就是由其上面dp[ i - 1 ][ j ]和左上角dp[ i - 1 ][ j - w[ i ] ]的值求得,所以我们初始化dp数组第一行第一列就可以。第一列背包空间为0,全部初始化为 0 ,第一行根据第 0 个物品的体积和背包大小比较来初始化即可。

遍历顺序:

        其实先遍历背包或物品都是可以的,无非是一个以行遍历,一个以列遍历,通过模拟发现都是可以求出对应值的,一般先便利物品,方便理解。

图解:

        给出初始化和代码执行流程的模拟,配合图来理解会更加深刻。

动态规划:0-1背包、完全背包问题 | 详细原理解释 | 代码及优化(C++),Leetcode,算法,leetcode,c++,数据结构

实现代码:

        这里只给出主要代码,根据具体问题自行添加其他代码即可。

dp数组初始化:

// 二维数组,n 物品个数
vector<vector<int>> dp(n, vector<int>(bagw + 1, 0));

// 初始化
for (int j = w[0]; j <= bagw; j++) 
{
    dp[0][j] = v[0];
}

遍历:

// n 物品个数 ,m 背包大小
// 遍历物品
for (int i = 1; i < n; i++)
{
    //遍历背包
    for (int j = 0; j <= m; j++)
    { 
        if (j < w[i]) dp[i][j] = dp[i - 1][j];
        else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);

    }
}

优化:

原理:

        其实就是把二维数组变为一维数组,我们在二维遍历时,会发现在其求的值仅仅是用了上一层的数,而用不到其他的数字,所以我们就可以只维护一层数组,不断的更新本层的数来达到降维的作用。所以递推的公式和遍历的顺序就要发生改变。

递推公式:

i 不放入:dp[ j ] = dp[ j ]

i 确定放入:dp[ j ] = dp[ j - w[ i ] ] + v[ i ]

求最大:max(dp[ j ], dp[ j - w[ i ] ] + v[ i ])

遍历顺序:

        首先,优化后,我们只能先遍历物品,而不能先背包,毕竟我们模拟的是二维中先遍历背包的一层数组。

        其次,在遍历内层背包时,我们只能倒序遍历,从大向小,从后向前,因为我们在二维中递推公式用的是左上角和上面的数求得,若从前向后遍历,根据递推公式,我们不断的更新了左侧的数,会使后面的数得到的是更新后的数,而不是原本上一层的数,而倒序就可以避免这个问题。

        简单来说就是二维数组情况下,使用 i - 1 行的已知最大价值来推断,是左上角和上面的数据,但是换成一维数组的话,左上角的数据就是左边的数据,因此,只能从右边开始遍历背包的容量,如果从左边开始遍历的话,就会导致重复计算。

实现代码:

初始化:

// 初始化
vector<int> dp(n + 1, 0);

遍历:

        两种方法一样,第一种和二维对应方便理解,而第二种比较简洁,因为一维用的是用一个数组,我们不去改变数的值就表示把自己赋值给自己的操作了。

// n 物品个数 ,m 背包大小
// 遍历物品
for (int i = 1; i <= n; i++)
{
    for (int j = m; j >= 0; j--)
    {
        if (j >= w[i]) dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
        else dp[j] = dp[j];
    }
}
// n 物品个数 ,m 背包大小
// 遍历物品
for (int i = 0; i < n; i++)
{
    // 遍历背包
    for (int j = m; j >= w[i]; j--)
    {
        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);

    }
}

完全背包

问题描述:

        完全背包就是 01 背包的物品可以用多次。

解析:

        写 01 背包代码的时候说了物品从前向后遍历会导致物品多次计算。而多重背包就是要多次取同一个物品,正好就对上了,所以我们的代码就很明确了。文章来源地址https://www.toymoban.com/news/detail-668208.html

实现代码:

// n 物品个数 ,m 背包大小
// 遍历物品
for (int i = 0; i < n; i++)
{
    // 遍历背包
    for (int j = w[i]; j <= m; j++)
    {
        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);

    }
}

到了这里,关于动态规划:0-1背包、完全背包问题 | 详细原理解释 | 代码及优化(C++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 完全背包&多重背包问题(动态规划)

    完全背包问题: 每个物品使用次数没有限制,与0-1背包的不同之处在于 遍历背包的顺序 是正序。 多重背包问题: 与完全背包的区别在于,每一种物品是有个数限制的,不能无限选择。这篇博客讲解的非常详细,可以参考学习: 多重背包问题---超详细讲解+优化(不懂你揍我

    2024年04月10日
    浏览(36)
  • 【动态规划之完全背包问题】完全背包问题的通用解法与优化

    ⭐️ 前面的话 ⭐️ 本篇文章将介绍动态规划中的背包问题——完全背包问题,前面我们已经介绍了0-1背包问题,其实完全背包问题就只改了0-1背包问题的一个条件,即物品可选择次数由一次改为无数次,仅此而已,下面我们就来开始介绍完全背包问题。 📒博客主页:未见

    2023年04月22日
    浏览(38)
  • 动态规划——完全背包问题

    由于本人实力尚浅,接触算法没多久,写这篇blog仅仅是想要提升自己对算法的理解,如果各位读者发现什么错误,恳请指正,希望和大家一起进步。(●’◡’●) 了解完全背包问题前可以先去看看01背包问题(良心正解),先了解这个基础问题会更有利于你了解下面的完全背

    2024年02月04日
    浏览(34)
  • 动态规划:完全背包问题

    ACwing #3. 完全背包问题 完全背包问题和01背包问题很相似。 01背包问题每个物品只能选一个,而完全背包问题每个物品可以选无限次。 DP问题的关键是找到状态转移方程: ①定义f[i][j]表示从前 i 个物品中选择,体积为 j 的时候的最大价值。 ②那么转移方程f[i][j] = max(f[i - 1][j

    2023年04月19日
    浏览(35)
  • 算法系列--动态规划--背包问题(3)--完全背包介绍

    💕\\\"Su7\\\"💕 作者:Lvzi 文章主要内容:算法系列–动态规划–背包问题(3)–完全背包介绍 大家好,今天为大家带来的是 算法系列--动态规划--背包问题(3)--完全背包介绍 链接: 完全背包 可以发现完全背包问题和01背包问题还是特比相似的 分析: 完全背包问题 是 01背包问题 的推广

    2024年04月25日
    浏览(32)
  • 动态规划完全背包问题-java

    完全背包问题跟01背包问题思路大致一样,只不过对于物品的拿取次数不在限制,我们只需要考虑这点即可。 文章目录 前言 一、什么是完全背包问题? 二、问题模拟 1.样例数据 2.算法思路 三、代码如下 1.代码如下(示例): 2.读入数 3.代码运行结果 总结 完全背包问题跟

    2024年04月26日
    浏览(35)
  • 动态规划-----背包类问题(0-1背包与完全背包)详解

    目录 什么是背包问题? 动态规划问题的一般解决办法: 0-1背包问题: 0 - 1背包类问题  分割等和子集:  完全背包问题:  完全背包类问题 零钱兑换II: 背包问题(Knapsack problem)是一种组合优化的NP完全问题。 问题可以描述为:给定一组物品,每种物品都有自己的重量和价格

    2024年04月17日
    浏览(29)
  • 三十八、动态规划——背包问题( 01 背包 + 完全背包 + 多重背包 + 分组背包 + 优化)

    0 1 背包问题: 条件:N 个物品容量为 V 的背包,每件物品最多用 1 次,其中物品信息体积为 Vi,价值为 Wi。 目标:选出物品,使价值最大(不一定装满背包)。 特点:每件物品 最多只用 1 次 完全背包问题: 特点:每一件物品都有 无限个 多重背包问题: 特点:每个物品

    2024年02月07日
    浏览(36)
  • 动态规划:完全背包问题----中专生刷算法

    需要基础:闫氏dp分析法,01背包问题 先去看一下01背包问题,再看完全背包 动态规划:选择dp及优化01背包问题-CSDN博客 做过01背包问题的同学会发现,完全背包问题的代码 在01背包基础上改动很小,但是里面的思想,有很大差距 题目 有 N 种物品和一个容量是 V的背包,每种物品

    2024年04月16日
    浏览(37)
  • 力扣刷题-动态规划算法3:完全背包问题

    问题描述: 1)有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。 2) 每件物品都有无限个(也就是可以放入背包多次) (比0-1背包多出的条件) 3) 求解将哪些物品装入背包里物品价值总和最大。 求解步骤: 1)首先遍历物品,然

    2023年04月13日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包