完全背包问题(详细解答)

完全背包问题(详细解答)首先完全背包问题需要01背包问题做铺垫,如果读者01背包问题没有解决,一定要理解之后,在看完全背包问题,包括01背包的优化!这里是01背包这里是01背包的全部优化好,我们开始完全背包!完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。从定义中可以看出,与01背包的区别01背包最多只能拿一件物品,完全背包则不然,只要空间够多,一种物品我可以拿n件!01

大家好,又见面了,我是你们的朋友全栈君。

首先完全背包问题需要01背包问题做铺垫,如果读者01背包问题没有解决,一定要理解之后,在看完全背包问题,包括01背包的优化!
这里是01背包
这里是01背包的全部优化

好,我们开始完全背包!

完全背包定义

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

从定义中可以看出,与01背包的区别01背包最多只能拿一件物品,完全背包则不然,只要空间够多,一种物品我可以拿n件!

01背包的状态转移方程为:dp(i,j)=max(dp(i-1,j),dp(i-1,j-v[i])+val[i])
完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-v)+val[i])

我们可以看出,完全背包的动态转移方程max中第二项为i,而不是i-1。

为什么呢?

我们用01背包的思想去推导,完全背包的动态转移方程

完全背包状态转移方程推导

首先完全背包问题的动态转移方程可写为
(w为val[i]简写)(v=v[i]简写)

dp(i,j)=max(dp(i-1,j) , dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,
~~(以此类推到k) ,dp(i-1,j-k*v+kw))

我简单解释一下上面的方程,其实就是利用01背包思想,要求无限个物品,实际上我最多能装V/v[i]个 (总体积除以的单个个体积),所以我从装0个,到装一个,2个,3个,k个这里面一定有其中一个,是能产生最大的价值!

然后我们利用上述公式推导出”完全背包的状态转移方程”

开始推导
(时刻注意与这个方程的联系)

dp(i,j)=max(dp(i-1,j) , dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,
~~(以此类推到k) ,dp(i-1,j-k*v+kw))

推导开始

还是利用01背包思想
dp(i,j-v)=max( dp(i-1,j-v) , dp(i-1,j-2v)+w,dp(i-1,j-3v)+2w , dp(i-1,j-4v)+3w,~~
~依次类推到k , dp(i-1,j-kv)+(k-1)w) )

我们在这个方程两侧同时加上w,即可得到

dp(i,j-v)+w=max( dp(i-1,j-v)+w , dp(i-1,j-2v)+2w,dp(i-1,j-3v)+3w , dp(i-1,j-4v)+4w,~~dp(i-1,j-kv)+kw)

我们在回顾一下这个方程

dp(i,j)=max(dp(i-1,j) , dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,
~~(以此类推到k) dp(i-1,j-k*v)+kw))

可以发现dp(i,j-v)+w可以替代

dp(i-1,j-v)+w , dp(i-1,j-2v)+2w , dp(i-1,j-3v)+3w,~~, dp(i-1,j-k*v)+kw

所以我们得出
完全背包的状态转移方程:dp(i,j)=max(dp(i-1,j),dp(i,j-v)+w)

好了我们推导完成。
然后我们看下代码:

#include <iostream>
using namespace std;

int N,V;
int v[1010],val[1010];
int dp[1010][1010];
int main()
{ 
   
    scanf("%d%d",&N,&V);
    for(int i=1; i<=N; i++)
    { 
   
        scanf("%d%d",&v[i],&val[i]);
    }
    for(int i=1; i<=N; i++)
        for(int j=0; j<=V; j++)
        { 
   
            dp[i][j]=dp[i-1][j];//继承上一个背包
            if(j>=v[i])
            { 
     //完全背包状态转移方程
                dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+val[i]);
            }
        }
    printf("%d",dp[N][V]);
    return 0;
}

从宏观上理解,为什么会这样呢?
在这里插入图片描述

我从代码的角度阐释一下这个问题!
注意我们现在并没有对dp数组进行降维!
我们的j是从0开始的,依次递增这个是完全背包的关键,也是与01背包本质的区别
dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+val[i]);
首先要满足完全背包的动态转移方程,就要先知道dp(i,j-v)的大小
正好我们是从0开始的,并不是从后往前,也就是当求到dp(i,j)时
dp(i,j-v),在前面已经求过!!!
所以我们可以应当理顺的求出dp(i,j)而不再是向01背包要考虑前i-1时候的状态!

完全背包的优化

然后我们根据01背包的优化原则对,完全背包进行优化!
优化后的动态方程
dp[j]=max(dp[j],dp[j-v]+w)

代码(里面有一个点需要理解,我写在注释里了)

#include <iostream>
using namespace std;

int N,V;
int v[1010],val[1010];
int dp[1010];
int main()
{ 
   
    scanf("%d%d",&N,&V);
    for(int i=1; i<=N; i++)
    { 
   
        scanf("%d%d",&v[i],&val[i]);
    }
    for(int i=1; i<=N; i++)
        for(int j=0; j<=V; j++)
        { 
   
            dp[j]=dp[j];//此时右边的dp[j]是上一层i-1的dp[j],然后赋值给了当前i的dp[i]
            if(j>=v[i])
            { 
   
                dp[j]=max(dp[j],dp[j-v[i]]+val[i]);//dp[j-v[i]],已经被算过
            }           
        }
    printf("%d",dp[V]);//输出最大体积,即最优解

    return 0;
}

感谢观看,希望大家多多支持一键三连!!
嘻嘻~~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/147830.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • FTP的20、21端口,工作模式

    FTP的20、21端口,工作模式

    2021年9月23日
    66
  • Win10 下报错 WerFault.exe -解决方法亲测有效

    Win10 下报错 WerFault.exe -解决方法亲测有效Win10WerFault.exe错误装了后经常出现WerFault.exe的应用程序错误提示。内存*****地址不能为read.解决方法两种:1.系统设置2.管理员运行cmd命令行模式我机器用的第二种方式。1.系统设置1.1本地组策略gpedit.msc用户配置-管理模块-Windows组件-Windows错误报告-禁用1.2…

    2022年6月29日
    24
  • 【C++】自引用this指针的秘密

    【C++】自引用this指针的秘密关于this指针的一个经典回答当我们在进入一个房子之后,可以看见房子里的桌子、椅子、地板等,但是看不到房子的全貌。对于一个类的实例来说,你可以看到它的成员函数、成员变量,但是实例本身呢?this是一个指针,它时时刻刻指向这个个实例。识别一个类可以分为哪三步?①识别类名。②识别数据成员。③识别成员函数并修改之。this指针的特性:①this指针的类型:类类型*const。②thi…

    2022年5月16日
    53
  • 河北专接本计算机专业课平均分,2019年河北专接本招生数据及通过率分析[通俗易懂]

    河北专接本计算机专业课平均分,2019年河北专接本招生数据及通过率分析[通俗易懂]每天都会有很多的同学咨询小编河北专接本各个专业的通过率,其实对于单科的通过率来说并不能作为你专接本选专业的首要因素,因为专接本的分数充满的随机性,同学们往往会被某专业专业的高通过率所迷惑从而做出错误的选择。那么易学仕小编整理了一下河北专接本2019年的通过率,仅供大家参考!经管类是财经类和管理类,19年刚刚合并为经管类!这个大类一共招收2667人,参加考试达到100分以上的人数是8686人,整体通…

    2022年7月16日
    36
  • 【电赛】2017年电赛A题——三相逆变电源EG8030测试

    【电赛】2017年电赛A题——三相逆变电源EG8030测试目录:一、相关介绍1.创建窗口【Tk】2.创建标签【Label】3.创建按钮【Button】二、简易滚动抽奖界面代码三、界面展示注:本文仅用于学习交流分享,[若有不妥之处,请指正,感谢]关键词:【电赛】【三项逆变电源】【EG8030】用到的工具有:AltiumDesigner16.0实现的功能有:①实现三相SPWM②实现三相交流电一、相关介绍SPWM:脉冲宽度按正…

    2022年5月5日
    117
  • 关于行列满秩矩阵的一个小结论

    关于行列满秩矩阵的一个小结论文章目录行列满秩矩阵的定义小结论 证明小结论 的一个小应用小结论 行列满秩矩阵的定义若矩阵的行 列 向量组线性无关 Rightarrow 该矩阵称为行 列 满秩的小结论 若一个 s ns ns n 的矩阵 AAA 的秩为 rrr s r Rightarrow exists r s r 的列满秩矩阵 BBB 和 r nr nr n 的行满秩矩阵 CCC 使得 A BCA BCA BC 注意 是列满秩 行

    2025年9月2日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号