目录
基本介绍
问题描述
有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
基本原理
动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。但不同的是,分治法在子问题和子子问题等上被重复计算了很多次,而动态规划则具有记忆性,通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。
解决过程
定义参数:Vi 表示第 i 个物品的价值,Wi 表示第 i 个物品的体积,
定义 V(i, j):当前背包容量 j,前 i 个物品最佳组合对应的价值,同时背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品选或不选)。
1、建立模型,即求:;
2、寻找约束条件:;
3、寻找递推关系式,面对当前商品有两种可能性:
- 包的容量比该商品体积小,装不下,此时的价值与前 i-1 个的价值是一样的,即 V(i, j) = V(i-1, j);
- 还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即 V(i, j) = max{V(i-1, j),V(i-1, j-w(i)) + v(i)}。其中 V(i-1, j)表示不装,V(i-1, j-w(i)) + v(i) 表示装了第 i 个商品,背包容量减少 w(i),但价值增加了 v(i);
由此可以得出递推关系式:
4、填表,初始化边界条件,V(0, j) = V(i, 0) = 0;
5、表格填完,即可得到最优解。
Python代码
动态规划
N = 5
C = 10
w = [2, 2, 6, 5, 4] # 自定义物品重量
v = [6, 3, 5, 4, 6] # 自定义物品价值
f = [[0 for j in range(C+1)] for i in range(N+1)]
y = [0]
x = range(N*C+1)
for i in range(1, N+1):
for j in range(1, C+1):
if j < w[i-1]:
f[i][j] = f[i-1][j]
else:
if f[i-1][j-w[i-1]] + v[i-1] > f[i-1][j]:
f[i][j] = f[i-1][j-w[i-1]] + v[i-1]
else:
f[i][j] = f[i-1][j]
y.append(f[i][j])
绘制图像
plt.plot(x, y, label="动态规划算法", color="red", linestyle="--", marker="s", markersize=4)
xlabel = [0]
for x in range(1, N*C+1):
xlabel.append(x)
plt.xticks(xlabel)
plt.xlabel("迭代次数")
plt.ylabel("最大价值")
plt.title("0-1背包问题的算法分析图")
plt.legend()
# plt.savefig(Path(__file__).name[0:-3]+".pdf")
plt.show()