动态规划——完全背包问题

这篇具有很好参考价值的文章主要介绍了动态规划——完全背包问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

由于本人实力尚浅,接触算法没多久,写这篇blog仅仅是想要提升自己对算法的理解,如果各位读者发现什么错误,恳请指正,希望和大家一起进步。(●’◡’●)

完全背包问题

了解完全背包问题前可以先去看看01背包问题(良心正解),先了解这个基础问题会更有利于你了解下面的完全背包问题(个人观点)

题目

动态规划——完全背包问题,数据结构与算法,# 动态规划,动态规划,算法,c++,数据结构

思路

重要变量说明:
f[][[]:用于状态表示;
w[]:记录每个物品的价值;
v[]:记录每个物品的体积

  1. 定义二维数组f[][],其中f[i][j]表示在前i个物品,背包容积为j的限制下所能装下的最大价值。这里的f[i][j]就是做法的集合,f[i][j]的值就是最大价值即属性。
  2. i=1开始枚举,对于第i个物品,都有无数种选择(看似是无数种,其实还是有限制的):
    • 如果不选第i个物品,那么状态转移方程为f[i][j]=f[i-1][j]
    • 如果选择第i个物品一次,那么状态转移方程为f[i][j]=f[i-1][j-v[i]]+w[i]
    • 如果选择第i个物品二次,那么状态转移方程为f[i][j]=f[i-1][j-2*v[i]]+2*w[i]
    • ......
    • 如果选择第i个物品k次,那么状态转移方程为f[i][j]=f[i-1][j-k*v[i]]+k*w[i]
  3. 我们因为要求最大价值,所以对上面两种情况去max即可

我们发现其实上面的思路大致上和01背包问题差不多,只不过对于每一个物品i,我们不止两种选择(选与不选)而是有无数种选择。所以我们可以在01背包问题的基础上,在两层循环中再套一层循环,表示选择第i个物品多少次。

代码(不优化版,二维数组)

#include<iostream>

using namespace std;
const int N=1010;
int f[N][N],v[N],w[N];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]);
    for(int i=1;i<=n;i++)       //i表示当前选择到第i个物品,我们从第1个物品开始枚举,一直到n个物品
        for(int j=1;j<=m;j++)       //j表示当前背包的容积,我们从1开始枚举,一直到背包的最大的容积
            for(int k=0;k<=j/v[i];k++)      //k表示当前的选择第i个物品的次数,一直到所能选择的最大次数
                f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
    printf("%d\n",f[n][m]);
    return 0;
}

优化1(降低时间复杂度)

我们可以看到上面的思路虽然可以求解问题,但是时间复杂度是 O ( l o g 2 n ) O(log_2n) O(log2n),而题目给出的数据是 1 0 3 10^3 103,那么最后就是 1 0 9 10^9 109,而我们的要求是1s内,大概是 1 0 7 − 1 0 8 10^7-10^8 107108之间,所以我们还要优化

思路
f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w ,  f[i-1,j-2*v]+2*w , f[i-1,j-3*v]+3*w , .....)
f[i , j-v]= max(            f[i-1,j-v]   ,  f[i-1,j-2*v] + w , f[i-1,j-3*v]+2*w , .....)
由上两式,可得出如下递推关系: 
                        f[i][j]=max(f[i,j-v]+w , f[i-1][j]) 

还是没看懂的宝宝们可以可以看下面这份详细推理
动态规划——完全背包问题,数据结构与算法,# 动态规划,动态规划,算法,c++,数据结构

代码
#include<iostream>

using namespace std;
const int N=1010;
int f[N][N],v[N],w[N];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            {
                if(j>=v[i])
                    f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);
                else
                    f[i][j]=f[i-1][j];
            }
    printf("%d\n",f[n][m]);
    return 0;
}

思考

我们把完全背包问题和01背包问题做一下对比
01背包问题:f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);
完全背包问题: f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);
于是乎,聪明的你一定想到了完全背包问题的代码还可以优化,只使用一维数组,降低空间复杂度

优化2(降低空间复杂度)

具体为什么可以只用一维数组请看01背包问题

代码
#include<iostream>

using namespace std;
const int N=1010;
int f[N],v[N],w[N];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            {
                if(j>=v[i])
                    f[j]=max(f[j],f[j-v[i]]+w[i]);
                else
                    f[j]=f[j];
            }
    printf("%d\n",f[m]);
    return 0;
}

再思考

Q:为什么01背包问题使用一维数组时,枚举背包空间时要逆序,而完全背包问题使用一维数组时,枚举背包空间时是正序?
A:01背包问题中我们每次更新用的都应该是上一层即i-1层的数据,但是如果正序枚举背包空间j的话,在更新较大容积时,用到的就是已经污染的数据,即在第i层时,可能在j=v[i]时选了i这个物品,当j=2*v[i]时我们可能又选了i这个物品,而第i这个物品只能被选一次,而逆序枚举时,每次都只可能选择第i这个物品一次。但是在完全背包问题中我们就要用正序,因为我们要的就是已经更新的数据,因为每个物品都有无数个,所以可以选择第i个物品多次

如果你觉得我写题解还不错的,请各位王子公主移步到我的其他题解看看
数据结构与算法部分(还在更新中):
C++ STL总结 - 基于算法竞赛(强力推荐
最短路算法——Dijkstra(C++实现)
最短路算法———Bellman_Ford算法(C++实现)
最短路算法———SPFA算法(C++实现)
最小生成树算法———prim算法(C++实现)
最小生成树算法———Kruskal算法(C++实现)
染色法判断二分图(C++实现)
动态规划——01背包问题
Linux部分(还在更新中):
Linux学习之初识Linux
Linux学习之命令行基础操作

✨🎉总结

“种一颗树最好的是十年前,其次就是现在”
所以,
“让我们一起努力吧,去奔赴更高更远的山海”
动态规划——完全背包问题,数据结构与算法,# 动态规划,动态规划,算法,c++,数据结构
如果有错误❌,欢迎指正哟😋

🎉如果觉得收获满满,可以动动小手,点点赞👍,支持一下哟🎉文章来源地址https://www.toymoban.com/news/detail-762112.html

到了这里,关于动态规划——完全背包问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 动态规划-背包问题-完全背包

    对比01背包,完全背包中的每件物品有无数件。 也就是说,每件物品可以拿0,1,…,k,…件。 dp[i][j]表示前i种物品,体积为j时的最大价值 对于第i件物品: 不拿:dp[i][j]⇐dp[i-1][j] 拿一件:dp[i][j]⇐dp[i-1][j-w[i]]+v[i] 拿两件:dp[i][j]⇐dp[i-1][j-2w[i]]+2v[i] … 拿k件:dp[i]][j]⇐dp[i

    2024年04月08日
    浏览(37)
  • 动态规划之背包问题——完全背包

    算法相关数据结构总结: 序号 数据结构 文章 1 动态规划 动态规划之背包问题——01背包 动态规划之背包问题——完全背包 动态规划之打家劫舍系列问题 动态规划之股票买卖系列问题 动态规划之子序列问题 算法(Java)——动态规划 2 数组 算法分析之数组问题 3 链表 算法

    2024年02月03日
    浏览(30)
  • 完全背包&多重背包问题(动态规划)

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

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

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

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

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

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

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

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

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

    2024年04月25日
    浏览(31)
  • 动态规划完全背包问题-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)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包