背包问题是动态规划的经典题型,今天就背包问题中经典的01背包问题和完全背包问题做一下复习。
01背包问题
问题描述:有一个容量为W的背包,和N个物品,每个物品都有其相应的重量和价值。其中第i个物品的重量为
w[i]
,价值为v[i]
。请问这个背包最多能装的价值是多少?
在取物品时,我们受到两个因素的影响:背包的剩余容量和所取的物品。
我们定义 f(w,k)
为 当背包剩余容量为w时,现有k件物品可以取,所能够取到的最大价值。
对于每件物品,我们有两种选择: 取或者不取。取与不取的条件便是背包的剩余容量,如果背包当前的剩余容量大于当前物品的重量,则该物品可以取,否则该物品不取。
当物品太重,当前物品不取时,能够取到的最大价值便是取到前一个物品的最大价值。即 w[k]>w
时,f(w,k)=f(w,k-1)
。
当背包容量大于当前物品重量时,当前物品可以取。那么最大价值便是 f(w,k)=max(f(w,k-1),f(w-w[k],k-1)+v[k])
。
因此,状态转移公式:
1 | |-- f(w,k-1), w[k]>w (物品太重,背包放不下) |
代码实现:
1 | /** |
完全背包问题
完全背包是01背包的升级或变种,在01背包中,每件物品只有一件,因此在取的过程中,只能取0或1件。而在完全背包问题中,每件物品有无数件,每次取的时候,同一件物品可以取多次。
解决思路和01背包一致。
我们定义 f(w,k)
为当背包剩余容量为w时,现有k件物品可以取,所能够取到的最大价值。
同样,对于每件物品,也是有取和不取两种,其条件也是基于背包的剩余容量来判断。
当背包容量不足时,其状态转移和01背包一样,即 f(w,k)=f(w,k-1)
。
不同点在于背包容量足够装下当前物品时的状态。由于物品可以取多次,因此在取了当前物品时,物品数量还是k,而非01背包的k-1,因此完全背包问题中背包容量足够时状态:
f(w,k)=max(f(w,k-1), f(w-w[k], k)+v[k])
最终的完全背包问题的状态转移公式为:
1 | |-- f(w,k-1), w[k]>w (物品太重,背包放不下) |
实现代码:
1 | const solve = function (weights: number[], values: number[], W: number) { |