动态规划常见类型
题目一:01背包问题
一个背包总容量为V,现在有N个物品,第i个 物品体积为weight[i],价值为value[i],现在往背包里面装东西,怎么装能使背包的内物品价值最大?
例题:给定一个数m,将m拆成不同的自然数的和的形式有多少种方案,这就是典型的01背包问题,背包容量为m,物品件数为k,这里面的k是隐含条件,可以求出来,因为m最多由1+2+…+k得到,由此可以根据m求得物品件数的上限。
题目二:完全背包问题
一个背包总容量为V,现在有N个物品,第i个 物品体积为weight[i],价值为value[i],每个物品都有无限多件,现在往背包里面装东西,怎么装能使背包的内物品价值最大?
例题:假设现在有1元、2元、5元的纸币很多张,现在需要20块钱,你能给多少种找钱方案,这就可以认为是完全背包问题,即背包容量为20,物品体积分别为1、2、5。
题目三:最少硬币找零问题
给予不同面值的硬币若干种种(每种硬币个数无限多),如何用若干种硬币组合为某种面额的钱,使硬币的的个数最少?
在现实生活中,我们往往使用的是贪心算法,比如找零时需要13元,我们先找10元,再找2元,再找1元。如果我们的零钱可用的有1、2、5、9、10。我们找零18元时,贪心算法的策略是:10+5+2+1,四种,但是明明可以用两个9元的啊。这种问题一般使用动态规划来解决。
一、首先来看01背包问题
用一个数组f[i][j]表示,在只有i个物品,容量为j的情况下背包问题的最优解。第i个物品可以选择放进背包或者不放进背包(这也就是0和1),假设放进背包(前提是放得下),那么f[i][j]=f[i-1][j-weight[i]+value[i];如果不放进背包,那么f[i][j]=f[i-1][j]。
这就得出了状态转移方程:
f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]+value[i])
二、完全背包问题 和 硬币找零问题
其实这个两个问题非常相似,都是物品数目无限多,一个是不超过某个重量值W求最大value,一个是要获得某个value,求最小重量(每个硬币可以看成是重量为1的物品)。
(1)对于完全背包问题状态转移方程:
f[ i ] [ j ] = max( f[i-1][j], f[ i ][ j- weight[i] ] + value[i] ) ,注意后面是f[i, j-weight[i]],i 没有减1
可以理解为:j为背包可以容纳的重量,有i种物品时,对于第i种物品,要么取或者不取,至于取多少个我们并不关心。
(2)对于硬币找零问题状态转移方程:
f[i][j]=min( f[i-1][ j ], f [i ] [ j - value[i] ] + 1) ,注意后面是f[i, j-value[i]],i 没有减1
可以理解为:j为需要找零多少元,有i种硬币,找零时对于第i种硬币,我们只考虑取或者不取,至于取多少个我们并不关心!
两种边界情况说明一下:
(1)f[0][j]=Integer.MAXVALUE ,因为 对金额为 j 的钱找零,但是可以的硬币面值种类为0,这显然是无法做到的。其实这是一个”未定义“的状态。它之所以初始为Integer.MAXVALUE
(2)f[i][0]=0,因为,对金额为0的钱找零,可用来找零的硬币种类有 i 种,金额为0怎么找啊,故设置为0。
【推荐】FFA 2024大会视频回放:Apache Flink 的过去、现在及未来
【推荐】中国电信天翼云云端翼购节,2核2G云服务器一口价38元/年
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步