问题描述:
给定一些商品,包括商品的价格和体积,选定若干个商品装进固定容量的背包,选定商品的价格总和最大且总容量不超过背包容量。0-1背包问题仅有是否装入两种情况。
蛮力枚举
def KnapsackSR(i, c, vi, pi):
"""
:param pi: 商品价格的列表
:param vi: 商品体积的列表
:param i: 前i个商品
:param c: 容量为c时最优解
:return: 最大总价格
"""
if c < 0: # 如果背包容量小于0,返回负无穷
return float("-inf")
if i < 0: # 如果商品序号小于0,返回0
return 0
# P1为选择某种商品后进行递归求解
P1 = KnapsackSR(i - 1, c - vi[i], vi, pi)
# P2为不选择某种商品后进行递归求解
P2 = KnapsackSR(i - 1, c, vi, pi)
# 返回P1和P2之间的最大值,即为所求最优解
P = max(P1 + pi[i], P2)
return P
带备忘递归
- 方法一:
def KnapsackMR(i, c, vi, pi):
"""
:param i: 商品的序号
:param c: 背包容量
:param vi: 商品的体积
:param pi: 商品的价格
:return: 装进背包的容量对应的最大价格
"""
i_list = []
if c < 0:
return float("-inf"), []
if i < 0:
return 0, []
P1, i_list1 = KnapsackMR(i - 1, c - vi[i], vi, pi)
P2, i_list2 = KnapsackMR(i - 1, c, vi, pi)
P = max(P1 + pi[i], P2)
if P == P1 + pi[i]:
i_list.extend(i_list1)
i_list.append(i)
else:
i_list.extend(i_list2)
return P, i_list
- 方法二:
def KnapsackMR(i, c, vi, pi):
"""
:param i: 商品的序号
:param c: 背包容量
:param vi: 商品的体积
:param pi: 商品的价格
:return: 装进背包的容量对应的最大价格
"""
# 构造备忘录P[i,c],表示在前i个商品中选择,背包容量为c时的最优解
P = [[for j in range(c + 1)] for k in range(i + 1)]
if c < 0:
return float("-inf")
if i < 0:
return 0
P1 = KnapsackMR(i - 1, c - vi[i], vi, pi)
P2 = KnapsackMR(i - 1, c, vi, pi)
P[i][c] = max(P1 + pi[i], P2)
return P[i][c]
递推计算(动态规划)
import copy
def KnapsackDP(n, p, v, C):
"""
:param n: 商品数量
:param p: 各商品的价值
:param v: 各商品的体积
:param C: 背包容量
:return: 商品价格的最大值
"""
# 初始化,创建二维数组P[0...n,0...C]和REC[0...n,0...C]
P = [[0 for i in range(C + 1)] for j in range(n + 1)]
Rec = [[0 for i in range(C + 1)] for j in range(n + 1)]
# 求解表格,依次计算子问题
# 因为i是从1开始的,所以进行商品选择和记录时需要在原始基础上减1
for i in range(1, n + 1):
for c in range(1, C + 1):
# 选择商品i
if v[i - 1] <= c and (p[i - 1]+ P[i - 1][c-v[i - 1]]>P[i - 1][c]):
# 记录价格和决策
P[i][c] = p[i-1]+P[i-1][c-v[i-1]]
Rec[i][c] = 1
# 不选择商品i
else:
P[i][c] = p[i - 1][c]
Rec[i][c] = 0
# 输出最优解方案
K = copy.deepcopy(C)
for i in reversed(range(1, n + 1)):
if Rec[i][K] == 1:
print("选择商品序号(从1到n):", i)
K -= v[i - 1]
else:
print("不选择商品序号(从1到n):", i)
return P[n][C]
if __name__ == "__main__":
v = [10, 3, 4, 5, 4]
p = [24, 2, 9, 10, 9]
print("商品价格最大值:", KnapsackDP(len(v), p, v, 13)