动态规划可以一般按照下面的步骤进行:
1)、状态定义;
2)、状态转移方程;
3)、初始化;
4)、输出;
5)、思考状态压缩。
01背包问题:
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
1、题目描述:
https://www.acwing.com/problem/content/description/2/
2、题解:
用子问题定义状态:
即 dp[i][j] 表示前 i件物品恰放入一个容量为 j的背包可以获得的最大价值。
则其状态转移方程便是:dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i-1]]+w[i-1])。解释一下:
dp[i-1][j],不选第i-1个物品的背包的最大价值
dp[i-1][j-v[i-1]]+w[i-1],选第i-1个物品后的背包的最大价值(也即是剩余背包j-v[i-1]的容量的前i-1件物品,可以得到的最大价值+第i-1件物品的价值。
伪代码如下:
v[m]#体积数组
w[m]#价值数组
#初始化 ,m个物品,背包的总容量为n
dp[m+1][n+1]
dp[0][:] = 0
dp[:][0] = 0
for i in [1...m]:
for j in [1...n]:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-v[i-1]]+w[i-1])
return dp[m][n]
上面的时间和空间复杂度都是O(m*n),下面将优化空间复杂度,将为O(n)
当然可以进行空间优化,这时候第二个循环,也就是内循环要倒着来
伪代码如下:
v[m]#体积数组
w[m]#价值数组
#初始化 ,m个物品,背包的总容量为n
dp[n+1]
dp[:] = 0
for i in [1...m]:
for j in [n...1]:
dp[j] = max(dp[j],dp[j-v[i-1]]+w[i-1])
return dp[n]
下面附上上面两个伪代码的python代码:注意处理边界
基础版:
m,n = map(int,input().split())
v = [] #体积数组
w = [] #价值数组
for i in range(m):
num,x = map(int,input().split())
v.append(num)
w.append(x)
# print(m,n,v,w)
# dp = [[0] * (n+1)] * (m+1)
dp = [[0] * (n+1) for _ in range(m + 1)]
for i in range(1,m+1):
for j in range(1,n + 1):
if j < v[i-1]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-v[i-1]]+ w[i-1])
# print(dp)
print(dp[m][n])
优化版:
#空间优化
m,n = map(int,input().split())
v = [] #体积数组
w = [] #价值数组
for i in range(m):
num,x = map(int,input().split())
v.append(num)
w.append(x)
# print(m,n,v,w)
# dp = [[0] * (n+1) for _ in range(m + 1)]
dp = [0 for _ in range(n + 1)]
for i in range(1,m+1):
for j in range(n,0,-1):
if j < v[i-1]:
dp[j] = dp[j]
else:
dp[j] = max(dp[j],dp[j-v[i-1]]+ w[i-1])
# print(dp)
print(dp[n])
现在可以同步拿下LeetCode 416、474、494题。