动态规划之完全背包问题

牛客网例题为例,由于 leetcode没有经典例题可以讲解,牛客网这道可以当作模板题

题目分析

如果看过我的01背包分析,完全背包就是物品可以选无数多个

算法原理(第一小问)

第一小问就是不必装满(也就是可以装满也可以不装满)

1.状态表示:dp[i][j]:从前i个物品中,总体积不超过j的所有选法中,最大的价值

2.状态转移方程:

i位置的商品可分为不选/选1个/选2个/选3个等等

所以我们可以发现状态转移方程无非就是01背包问题的基础上可以选多个

但是这里发现选一个选两个选三个就是重复的有规律的,那我们就想能不能用一个状态去表示

优化

1.数学等价代换

首先我们根据状态转移方程写出最终的状态方程

我们发现i-1是不变的,j会变

所以我们尝试列出dp[i][j-v[i]]的状态转移方程

发现dp[i][j-v[i]+w[i]=dp[i][j]的后面的一大坨,此时就可以等价代换

所以最后的dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+w[i]);标红的是等价代换的

但是我们这里的j-[v[i]]可能不存在,所以我们在写代码的时候要先判断一下

 初始化

为什么第一列不用初始化?

因为我们在用dp【i】【j-v【i】】的时候是会先判断的

也就是j-v[i]>=0,才会用,如果是一列,j=0,只有v[i]=0才会进入,那你的dp[i][j-v[i]]=dp[i][0]

根本不会越界

第一行的初始化就是你没有商品的时候能不能凑出0/1/2/3的体积,显然不能,所以初始化为0

注意:填表的时候要清楚下标的映射关系

填表顺序

发现我们填某个位置的时候需要用到上一行和这一行左边的

所以我们填表要从上往下,从左往右 

返回值

dp[n][v]

算法原理(第二小问)

第一小问是不必装满

第二小问是必须装满

绿色代表新的状态表示:简单修改总体积正好等于j就行

因为你的状态是总体积刚好等于j,你要判断你这次加上这个能不能刚好等于j,所以你在找前面的时候你要判断前面是否能选出来j-v[i]的体积

我们这里用-1表示前面凑不出来总体积,为什么不用0

第一,你要想用0这个状态表示什么,是表示凑不出来,还是表示所有选法中最大的价值

第二,你如果用0去表示前面凑不出来,那max求dp[i][j-v[i]]+w[i]可能就会选到,

但你前面都凑不出来,你又把这一项选上了,这会导致全部的填表都是错误的

所以我们用-1来表示前面凑不出来

我们需要判断if(j-v[i]>=0&&dp[i][j-v[i]]!=-1)

红色表示前面有这个体积,绿色表示前面能凑出来,在+上i物品的体积就刚刚好

第一列也不用初始化,和上面一样 

 

代码编写

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值