01背包问题可参考上一篇动态规划之01背包问题。
有N种物品和一个容量为V的背包,第i种物品的体积为\(v_i\),价值为\(w_i\),每种物品有无限个(相当于可重复使用)。求解将哪些物品放入背包可以达到总价值最大。
这个问题非常类似01背包问题,特点是:每种物品有无数件,可以选择0件、1件、2件...直到\(V/v_i\)件。
用子问题定义状态:即\(F[i,j]\)表示前i件物品放入容量为j的背包,可以获得的最大价值。
状态转移方程:
这跟01背包问题一样有O(VN) 个状态需要求解,求解状态F[i,j]的时间是\(O(j/v_i)\),总的复杂度可以认为是\(O(NV\sum \frac V{v_i}))\),需要改进。
根据以上状态转移方程:
\(F[i,j] = max\{F[i-1,j], F[i-1,j-v_i] + w_i, F[i-1,j-2v_i] + 2w_i, ...\}\)
\(F[i,j-v_i] = max\{F[i-1,j-v_i], F[i-1,j-2v_i] + w_i, F[i-1,j-3v_i] + 2w_i, ...\}\)
可以得到优化后的状态转移方程:
对比01背包问题,只有表达式中的i与i-1有差异:
dp = [[0 for _ in range(max_V+1)] for _ in range(N)]
dp[i][j] = dp[i-1][j]
dp[i][j] = max(dp[i-1][j], dp[i][j-vi] + wi)
# 4种物品属性
v = [0, 1, 2, 3, 4]
w = [0, 2, 4, 4, 5]
N = len(v)
max_V = 5
dp = [[0 for _ in range(max_V+1)] for _ in range(N)]
for i in range(1, N):
for j in range(1, max_V+1):
if j < v[i]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-v[i]] + w[i])
print(dp[N-1][max_V])
输出结果:
一维数组的更新方式:
\(j >= v_i\)时,\(dp[j] = max(dp[j], dp[j-v[i]] + w[i])\)
由于v[i]是正数,dp[i][j-v[i]]在dp[i][j]前更新,顺序更新即可。
# 物品属性
v = [1, 2, 3, 4]
w = [2, 4, 4, 5]
N = len(v)
V = 5
dp = [0 for _ in range(V + 1)]
for i in range(N):
for j in range(v[i], V + 1):
dp[j] = max(dp[j], dp[j - v[i]] + w[i])
print(dp[V])
输出结果:
原文:https://www.cnblogs.com/ikventure/p/14877060.html