1. 硬币组合
如果我们有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?
假设d[i]为凑满i元所需最少的硬币数,那么:
d[i]
解释
d[0] = 0
0
d[1] = 1
需要从面值不大于1元的硬币中选择,结果为1
d[2] = d[2-1] + 1 = 2
从面值不大于2元的硬币中选择,符合要求的硬币面值为:1元
d[3] = d[3-3] + 1 = 1
符合要求的硬币面值为:1元/3元,含有3元的硬币d[3]=d[3-3]+1=1,不含3元的硬币d[3]=d[3-1]+1=d[2]+1 =3
...
...
可以得出状态转移方程:dp[i] = min(d[i-value[j]) + 1,参考代码:
import sys
# 需要用硬币凑满的钱数
amount = 12
# 硬币的种类
coins = [1, 3, 5]
def coin_dynamic(amount, coins):
dp = [0]
for i in range(1, amount + 1):
dp.append(sys.maxsize)
for j in range(len(coins)):
if coins[j] <= i and dp[i - coins[j]] + 1 < dp[i]:
dp[i] = dp[i - coins[j]] + 1
return dp
2. 0-1背包问题
假设我们有n件物品,分别编号为1, 2...n。其中编号为i的物品价值为value[i],它的重量为weight[i]。为了简化问题,假定价值和重量都是整数值。现在,假设我们有一个背包,它能够承载的重量是capacity。现在,我们希望往包里装这些物品,使得包里装的物品价值最大化,那么我们该如何来选择装的东西呢?
首先我们先构建一个表格dp[i][j],横轴为背包的容纳重量(从1到背包的实际最大容纳),纵轴为各个可选择的物品。而表格中的每个单元格表示的是使用i与前的物品、且保证总重量不大于j情况下背包能容纳物品的最大价值。
尝试填充完毕后,我们可以得到一个结论:在i行j列的最大值可以说是(i-1行[即不取i物品]j列的值) 和 (i物品的价值 + i-1行j-i物品价值列的值[即取了i物品的价值]),写成状态转移方程即为:`dp[i][j] = max{dp[i-1][j], dp[i-1][j-value[i]] + value[i]},对应的代码如下:
# n个物体的重量(w[0]无用)
weight = [1, 4, 3, 1]
# n个物体的价值(p[0]无用)
value = [1500, 3000, 2000, 2000]
# 计算n的个数
n = len(weight) - 1
# 背包的载重量
capacity = 5
# 装入背包的物体的索引
x