动态规划就是将问题划分为子问题,通过子问题的最优解得到原问题的最优解。动态规划把每个求解过程的子问题记录下来,下次碰到同样的子问题可以直接使用之前的结果。下面学习一类经典的背包问题。
1.背包问题
问题是这样的:n 件物品,每个重量 w[i],价值 c[i] 。背包容量 V。问如何使得背包内物品总价值最大。每种物品只有一件。
定义 dp[i][j] 表示前 i 件物品装入容量 j 的背包的价值,那么:
dp[i][j] = Math.max(
dp[i-1][j], // 不放第 i 件物品
dp[i-1][j-w[i]] + c[i] // 放第 i 件物品
)
因此代码如下:
for (int i = 0; i < n; i++) {
for (int j = w[i]; j <= V; j++) {
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-w[i]] + c[i]);
}
}
- 整体代码如下
"""
N=4,V=10
w1 = 8, c1 = 9
w2 = 3, c2 = 3
w3 = 4, c3 = 4
w4 = 3, c4 = 3
通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,
用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。
定义dp[i][j]为前i件物品装入容量为j的的背包的价值,即每放进一个物品就要
牺牲背包二点容量来获取背包的总价值
"""
import numpy as np
c=[0,9,3,4,3]
w=[0,8,3,4,3]
N=4
V=10
def 背包问题(N,w,c,V):
#既然是将物品放到背包,那么是以物品为主题,首先进行第一层循环,用w[i]可以遍历上一层的每一个商品的重量
dp = np.zeros((N+1, V+1), dtype=np.int32)
for i in range(1,N+1,1):
#然后再来第二层循环,j表示容量,j的最大值为容量V,最小值为必须大于当前遍历的物品的重量
for j in range(1,V+1,1): #这里出现一个问题:为什么每次要递减一,因为重量的最小单位就是1呀哈哈
if(j<w[i]):
dp[i,j]=dp[i-1,j] #如果说当前要装入的物品的重量大于背包的容量,直接返回未装之前背包的价值
else: #否则,我们挑选最大值未转这个物品之前背包的价值 和 装了之后背包的价值
dp[i,j]=max(dp[i-1,j],dp[i-1,j-w[i]]+c[i])
return dp
a=背包问题(N,w,c,V)
print(a)
2.复盘
在初始化一个dp二位数组的时候,应该注意到创建数组有三种办法
1.
a=[[]*11]*5
a[0].append(1)
print(a)
2.
b=[[] for j in range(5)]
for j in