题目:
有 N 件物品和一个容量为 V 的背包。放入第 i 件物品耗费的费用是 C i 1 ,得到
的价值是 W i 。求解将哪些物品装入背包可使价值总和最大。
状态转移方程:
F [i, v] = max {F [i − 1, v], F [i − 1, v − C i ] + W i }
基于递归的实现:
这里的出口容易搞错,出口可以从递推方程成立条件来考虑
def pack_0_1_Rec2(N,V,C,W):
if N == 0 :
return 0
if V < C[N-1]:
return pack_0_1_Rec(N-1,V,C,W)
return max(pack_0_1_Rec(N-1,V,C,W),pack_0_1_Rec(N-1,V-C[N-1],C,W) + W[N-1])
基于第一种递归的自下而上和自上而下实现:
# 后来仔细考虑出后之后,做了如下修正:
def pack_0_1_Top_down(N,V,C,W):
list = [[-1]*(V+1) for i in range(N+1)]
# mins = min(C)
# for i in range(N+1):
# for j in range(V+1):
# if i == 0 or j< mins:
# list[i][j] =0
list[0] = [0]*(V+1)
def pack_0_1_Top_down_(N,V):
# if list[N][V] == -1 and N >=1 and V >=mins:
if list[N][V] == -1 and N >=1:
A = pack_0_1_Top_down_(N-1,V)
if V < C[N-1]:
return A
else:
list[N][V] = max(A,pack_0_1_Top_down_(N-1,V-C[N-1])+W[N-1])
return list[N][V]
return pack_0_1_Top_down_(N,V)
def pack_0_1_bottom_up(N,V,C,W):
list = [[-1]*(V+1) for i in range(N+1)]
list[0] = [0]*(V+1)
for i in range(1,N+1):
for j in range(0,V+1):
A = list[i-1][j]
if j < C[i-1]:
list[i][j] = A
else:
list[i][j] = max(A,list[i-1][j-C[i-1]]+W[i-1])
# print list
return list[N][V]
01背包问题的一维数组方式实现
凡是基于去与不去的问题,均可使用如下方式
def pack_0_1_first(N,V,C,W):
def ZeroOnePack(F,ci,wi):
for v in range(V,ci-1,-1):
F[v] = max(F[v],F[v-ci] + wi)
return F
F =[0]*(V+1)
for i in range(1,N+1):
ZeroOnePack(F,C[i-1],W[i-1])
return F[V]
01背包问题可行性问题
可行性问题,想清楚初始条件
如果是,要求恰好装满背包,那么在初始化时除了 F [0] 为 0 ,其
它 F [1…V ] 均设为 −∞ ,这样就可以保证最终得到的 F [V ] 是一种恰好装满背包的最优解。
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将 F [0…V ] 全部设为 0 。
这是为什么呢?可以这样理解:初始化的 F 数组事实上就是在没有任何物品可以放入背包时的合法状态。
如果要求背包恰好装满,那么此时只有容量为 0 的背包可以在什么也不装且价值为 0 的情况下被“恰好装满”,
其它容量的背包均没有合法的解,属于未定义的状态,应该被赋值为-∞了。
如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为 0 ,
所以初始时状态的值也就全部为 0 了。
def pack_0_1_yes_or_no(N,V,C):
def ZeroOnePack(F,ci):
for v in range(V,ci-1,-1):
F[v] = F[v-ci] or F[v]
return F
F =[-1]*(V+1)
F[0] = True
for i in range(1,N+1):
ZeroOnePack(F,C[i-1])
return F[V]
运行结果:
#%%
N = 6
V = 23
C = [1,3,4,5,17,11]
W = [2,9,7,5,11,4]
#%%
print pack_0_1_Rec(N,V,C,W)
print pack_0_1_first(N,V,C,W)
print pack_0_1_Top_down(N,V,C,W)
print pack_0_1_bottom_up(N,V,C,W)
print pack_0_1_Rec2(N,V,C,W)
print pack_0_1_yes_or_no(N,V,C)
25
25
25
25
25
True