写在前面
-----------------------------------------------------------------------------------------------
声明:本文章仅供个人学习之用,由于作者能力有限,相关观点和信息仅供参考。
如有侵权请联系。
欢迎各位读者老爷提问和交流。
我们的目标是星辰大海!
------------------------------------------------------------------------------------------------
最近刷Leecode,遇到好多动态规划的问题,非常有趣。回顾一下动态规划的基础知识。
1.动态规划基础概念
动态规划的三要素:最优子结构,边界,状态转移函数
最优子结构:每个阶段的最优状态可以从之前的某个阶段的某个状态可以直接得到。简单来说,就是子问题或者子结构的最优解能够解决这个问题的最优解。
边界:问题最小子集的解。
状态转移函数:两个相邻子问题之间的关系递推式,更新函数,跃迁函数,随便怎么叫。
动态规划本身是一个用空间换时间的算法。
任何一类动态规划问题都是先建(dp)表。
对于每一个子问题只计算一次,然后将计算的结果保存在一个表格内对应的问题,需要上一个子问题解的时候,只需要调用就行,所以时间复杂度为o(1)
(注意细节,和递归的对比)
什么时候用?
枚举所有可能的情况,多半是深度优先搜索和动态规划问题。
经典案例赏析
2. 背包问题案例
题目:现在有4个物品,背包容量为8,背包最多多能装入价值为多少的物品?
物品信息 | 物品体积 | 物品价值 |
商品1 | 2 | 3 |
商品2 | 3 | 4 |
商品3 | 4 | 5 |
商品4 | 5 | 6 |
核心思路
1.建立一个dp表(一言不合先建表)
2.如果装不下当前物品,说明当前n个物品的最优解和前n-1个物品的最佳组合是一样的。
3.如果能装的下当前物品。
可能1:装当前物品,在背包空间允许的情况下,前n-1个物品的最优解加上当前物品的价值就是新的最优解。
可能2:背包空间不允许装当前物品,那么前n个物品的最优解和前n-1个物品的最优解是一样的。
(注意可能2和第二项思路的区别,可能2是,我有空间,但是可以选择不装这个。)
原因在于:
我们需要选取可能1和可能2中,价值最高的那个选择,称为新的最优解(转移函数为max,在本题中)。
表格模拟
step1.背包容量是输入给的,只有商品1
注意dp表往往长度都是n+1,原因是0作为初始的对比的状态
这里的主观理解也比较简单,0号商品价值为0,体积为0,怎么填充都是0。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | ||||||||
2 | 0 | ||||||||
3 | 0 | ||||||||
4 | 0 |
商品1的体积为2,价值为3,
也就是,假设只有商品1,那么体积为8的背包可以装的情况有,1件商品1,2件商品1,3件商品1,4件商品1.
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 3 | 6 | 9 | 12 | ||||
2 | 0 | ||||||||
3 | 0 | ||||||||
4 | 0 |
填充完满后,展示如下
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 12 |
2 | 0 | ||||||||
3 | 0 | ||||||||
4 | 0 |
也就是说:如果只有商品1,我们可以选4种方案,带来的价值为4种。
step2,有商品1和商品2
商品1体积为2,商品2体积为3,所以上半区的分布如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 12 |
2 | 0 | 0 | 3 | 4 | |||||
3 | 0 | ||||||||
4 | 0 |
注意这里,当背包容量为3的时候,只可以装一件商品1或者商品2,因此在同等空间下,装一件商品2价值是最大的。
上面是主观逻辑表示,那么用算法逻辑描述,则这里的表述如下:
背包容量为3,物品为商品1,商品2:
(1)判断当前背包容量是否能够装下物品:能
(2)判断当前状态(dp[i][j])装下该物品后的总价值(4)和上一子阶段(dp[i-1][j])的总价值(不装该物品的总价值(3))哪个更大?
结论,装该物品,更新最新的最优解为价值4.
同理:最后的图如下所示
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 3 | 3 | 6 | 6 | 9 | 9 | 12 |
2 | 0 | 0 | 3 | 4 | 6 | 7 | 9 | 10 | 12 |
3 | 0 | 0 | 3 | 4 | 6 | 7 | 9 | 10 | 12 |
4 | 0 | 0 | 3 | 4 | 6 | 7 | 9 | 10 | 12 |
代码实现
def dp():
n = 4
w = [2,3,4,5]
v = [3,4,5,6]
c = 8
#构建一个dp表
# value = [[0 for j in range(c+1)] for i in range(n+1)]
value = [[0]*(c+1) for i in range(n + 1)]
# print(value)
for i in range (1,n+1):
for j in range(1,c+1):
if(w[i-1]>j):
value[i][j]=value[i-1][j]
else:
value[i][j]=max(value[i-1][j],value[i][j-w[i-1]]+v[i-1])
# print(value)
print("最大价值为:",value[n][c])
x=[False for i in range(n)]
j=c
for i in range(0,n):
if value[i][j]>value[i-1][j]:
x[i-1]=True
j=j-w[i-1]
print("背包中所装物品为:")
for i in range(n):
if x[i]:
print("第{}个".format(i+1))