目录
完全背包(每件物品可以选无限次)
01背包
1.题目描述
2.解题思路
f[i][j]:表示只看前i个物品,总体积是j的情况下,最大价值是多少
返回max{f[N][0~V]}
当前物品可以装的下(if v[i]<=j)时:
1.选第i个物品:f[i][j]=f[i-1][j-v[i]]+w[i]
2.不选第i个物品:f[i][j]=f[i-1][j]
f[i][j]=max{1. , 2. } 两种情况取最大值
当前物品装不下(if v[i]>j)时:
f[i][j]=f[i-1][j]
注意初始化方式:
如果f[j]表示体积小于等于j的最大价值,那么f[]应该全部初始化成0;
如果表示体积恰好是j的最大价值,那么f[]应该初始化成负无穷(除了f[0] = 0)
- 那么为什么当表示体积小于等于j时的最大价值时,要初始化成0呢? 这里最好从原始状态来考虑:dp的边界是f[0][j],表示一个物品都不选,体积不超过j的最大价值,那么“一件物品都不选”这个方案是合法的,它的价值是0,因此需要把f[0][j]初始化成0。
- 当表示体积恰好等于j时的最大价值时,还是从定义出发,f[0][j],表示一件物品都不选,体积恰好是j的最大价值,那么只有当j == 0时有合法方案,j等于其他值时没有合法方案,因此只有f[0][0] = 0,其余f[0][j] = -INF。
3.代码实现
N,V = list(map(int,input().split()))
v=[]
w=[]
v.append(0)
w.append(0)
for _ in range(N):
v_, w_ =list(map(int,input().split()))
v.append(v_)
w.append(w_)
f=[[0 for _ in range(V+1)] for _ in range(N+1)]
for i in range(1,N+1):
for j in range(0,V+1):
f[i][j]=f[i-1][j]
if v[i]<=j:
f[i][j]=max(f[i-1][j-v[i]]+w[i],f[i][j])
res=0
for j in range(0,V+1):
res=max(res,f[N][j])
print (res)
4.代码优化
其实数组每次写入一行数据都是根据上一行的数据进行写入,不需要用二维数组,可以用一维数组,每次根据自身进行更新即可,重点是[i-1][j - v[i]]这个数据的意思是我要在表中上一行找比j小的数据,那换成一维的话,我找的是自身(只有一行,没有上一行)j左边的数据,这个数据必须保证是上一次(i-1)写入的,肯定不能从左向右写入数据,那样的话[i-1][j - v[i]] 对应的就是这一次(i)写入的,上一次数据没有利用就丢失了,所以j循环应该从V到1,从右向左向一维数组写d入数据。
N,V = list(map(int,input().split()))
v=[]
w=[]
v.append(0)
w.append(0)
for _ in range(N):
v_, w_ =list(map(int,input().split()))
v.append(v_)
w.append(w_)
# 如果f[j]表示体积小于等于j的最大价值,那么f[]应该全部初始化成0;
# 如果表示体积恰好是j的最大价值,那么f[]应该初始化成负无穷(除了f[0] = 0)
f=[0 for _ in range(V+1)]
for i in range(1,N+1):
for j in range(V,-1,-1):
if v[i]<=j:
# 如果j像优化之前的代码正向算,那实际代表的是i那层的j,而我们需要的是i-1那层的是j
f[j]=max(f[j-v[i]]+w[i],f[j])
print (f[V])
参考:https://www.acwing.com/problem/content/video/2/
参考:https://blog.csdn.net/m0_37907835/article/details/78991461
完全背包
1.题目描述
2.解题思路
和01背包的区别:每件物品可以选无限次
直接上一维:
j从大到小枚举:f[j-v[i]]是i-1状态的 f[i-1][[j-v[i]]
j从小到大枚举:f[j-v[i]]是i状态的f[i][[j-v[i]],此时这个j-v[i]在之前被算过了,已经包含第i个物品了,因为当前这个i是可以取无限个的,所以应该包含这个i
3.代码实现
N,V = list(map(int,input().split()))
v=[]
w=[]
v.append(0)
w.append(0)
for _ in range(N):
v_, w_ =list(map(int,input().split()))
v.append(v_)
w.append(w_)
# 如果f[j]表示体积小于等于j的最大价值,那么f[]应该全部初始化成0;
# 如果表示体积恰好是j的最大价值,那么f[]应该初始化成负无穷(除了f[0] = 0)
f=[0 for _ in range(V+1)]
for i in range(1,N+1):
for j in range(0,V+1):
if v[i]<=j:
# 如果j像优化之前的代码正向算,那实际代表的是i那层的j,而我们需要的是i-1那层的是j
f[j]=max(f[j-v[i]]+w[i],f[j])
print (f[V])
二维费用的背包
1.题目描述
2.解题思路
费用限制为重量和体积,每个物品个数只有1个
3.代码实现
N,V,M = list(map(int,input().split()))
v=[]
m=[]
w=[]
v.append(0)
m.append(0)
w.append(0)
for _ in range(N):
v_, m_, w_ =list(map(int,input().split()))
v.append(v_)
m.append(m_)
w.append(w_)
f=[[0 for _ in range(M+1)] for _ in range(V+1)]
for i in range(1,N+1):
for j in range(V,-1,-1):
if v[i]<=j:
for k in range(M,-1,-1):
if m[i]<=k:
f[j][k]=max(f[j-v[i]][k-m[i]]+w[i],f[j][k])
print (f[V][M])
多重背包
1.题目描述
2.解题思路
多加一层循环,用于限制每个物品的使用个数
初始化时如果把f当中的所有元素初始化为0,求f[V]
初始化时如果f[0]=0,其余元素为--INF,求max{f[0~V]}
3.代码实现
N,V = list(map(int,input().split()))
v=[]
w=[]
s=[]
v.append(0)
w.append(0)
s.append(0)
for _ in range(N):
v_, w_, s_ =list(map(int,input().split()))
v.append(v_)
w.append(w_)
s.append(s_)
f=[0 for _ in range(V+1)]
for i in range(1,N+1):
for j in range(V,-1,-1):
k=1
while k<=s[i] and k*v[i]<=j:
f[j]=max(f[j-k*v[i]]+k*w[i],f[j])
k+=1
print (f[V])
扩展多重背包.扩大数据范围
1.题目描述
2.解题思路
可以将s拆成s份,每个物品选或者不选,只能选一次,转换成0,1背包问题,但是这样复杂度还是不满足条件
考虑一个数s,至少选择(logs)向上取整个数才可以表示出0~7所有的数(将每个数转化为二进制表示,则每个位可以选或不选(1或0))
考虑10这个数,如果选择1,2,4,8四个数,会表示出0~15的每种情况,多出不需要的11~15,如果1,2,4,(10-7)这四个数就可以恰好表示0~10了:
s=s-1-2-4-...... 直到小于0为止,剩下的那个数就是需要后补的
因此,我们可以把问题转成01背包问题了,只需判断这logs个数选或者不选即可
3.代码实现
N,V = list(map(int,input().split()))
v=[]
w=[]
s=[]
v.append(0)
w.append(0)
s.append(0)
for _ in range(N):
v_, w_, s_ =list(map(int,input().split()))
v.append(v_)
w.append(w_)
s.append(s_)
# 存入的是一个合并后的物品的元组 (v_, w_)
goods=[]
f=[0 for _ in range(V+1)]
# 合并物品
for i in range(1,N+1):
k=1
while k<=s[i]:
s[i]-=k
goods.append((k*v[i],k*w[i]))
k=k*2
# s-1-2-4-......剩下的
if s[i]>0:
goods.append((s[i]*v[i],s[i]*w[i]))
# 01背包过程
for good in goods:
for j in range(V,-1,-1):
if good[0]<=j:
f[j]=max(f[j-good[0]]+good[1], f[j])
print (f[V])