一、动态规划
1、动态规划的定义
动态规划是将原始问题划分为若干个子问题,通过仅求解每个子问题一次,并将其结果保存在一个表结构中,以后用到的时候直接存取的方法。
2、适用于动态规划的问题
① 优化子结构
优化子结构,即一个问题的优化解包含了子问题的优化解。
② 重叠子问题
在问题求解过程中,很多子问题的解被多次使用。
3、动态规划算法步骤
① 分析优化解的结构
② 建立状态转移方程(递归方程)
③ 自底向上地求解各个子问题
一是计算优化解的代价并保存
二是获取构造最优解的信息并保存
④ 根据构造最优解的信息来构造优化解
二、动态规划求解0-1背包问题
给定n种物品和一个背包,物品i的重量是, 价值 , 背包承重为C, 问如何选择装入背包的物品,使装入背包中的物品的总价值最大?
以下方算例为例,求解0-1背包问题。
物品 | 重量 | 价值 |
---|---|---|
1 | 2 | 6 |
2 | 2 | 3 |
3 | 6 | 5 |
4 | 5 | 4 |
5 | 4 | 6 |
背包最大承重C为10。
1、基本模型
① 分析优化解结构
(1)
(2)
(3)
子问题v[i][j]表示只允许前i件物品放入容量为j的背包内可以获得的最大价值。
② 建立状态转移方程
(1) 第一种情况
若第i件物品重量大于背包最大承重j,那么该子问题转化为前i-1件物品放入容量j背包内可以获得的最大价值,即
v[i][j] = v[i-1][j]
(2) 第二种情况
若第i件物品重量小于等于背包最大承重j,那么该子问题转化为 前i-1件物品放入容量j背包内可以获得的最大价值 与 前i-1件物品放入容量为j-背包内可以获得的最大价值 的最大值,即
v[i][j] = max {v[i-1][j],v[i-1][j-]}
③ 自底向上地求解各个子问题
一是计算优化解的代价并保存
二是获取构造最优解的信息并保存
④ 根据构造最优解的信息来构造优化解
该问题最优解的值即为v[n][C]
2、代码求解
import numpy as np
# 求解0-1背包问题:n为物品数量;weight为背包最大承重;
# weight_list为物品重量表;value_list为物品价值表;
def bag(n, weight, weight_list, value_list):
# value_mat保存最优解的代价
value_mat = np.zeros((n + 1, weight + 1))
# object_mat保存获取最优解的信息
object_mat = [[] for i in range(n + 1)]
# 自底向上地求解各个子问题
for i in range(1, n + 1):
for j in range(weight + 1):
# 第一种情况
if weight_list[i - 1] > j:
value_mat[i][j] = value_mat[i - 1][j]
object_mat[i].append(0)
# 第二种情况
else:
if value_mat[i - 1][j] >= value_list[i - 1] + value_mat[i - 1][j - weight_list[i - 1]]:
value_mat[i][j] = value_mat[i - 1][j]
object_mat[i].append(0)
else:
value_mat[i][j] = value_list[i - 1] + value_mat[i - 1][j - weight_list[i - 1]]
object_mat[i].append(i)
# 求解该问题的最优解
best_value = value_mat[n][weight]
object_list = []
x = n
y = weight
# 求解获取该问题最优解的信息
while x > 0 and y > 0:
if object_mat[x][y] != 0:
object_list.append(object_mat[x][y])
x -= 1
y -= weight_list[x - 1]
else:
x -= 1
object_list.reverse()
# 返回最优解及其信息
return best_value, object_list
# 求解该算例
value, objects = bag(5, 10, [2, 2, 6, 5, 4], [6, 3, 5, 4, 6])
print(value, objects)
3、输出结果
15.0 [1, 2, 5]