题目:
解答:
方法一:
N,V=map(int,input().split()) #输入物品种数和背包容量
m=[0]*(V+1) #新建一个长度为V+1的list m
for i in range(N):
v,w,s=map(int,input().split()) #输入第i种物品的体积、价值和数量
if s==-1: #第i种物品只能用1次,01背包
for j in range(V,-1,-1):
if v<=j:
m[j]=max(m[j],m[j-v]+w) #每次只能取一个
elif s==0: #第i种物品可以用无限次,完全背包
for j in range(v,V+1):
m[j]=max(m[j],m[j-v]+w) #每次可以取多个
else: #第i种物品最多只能用si次,多重背包
for j in range(V,-1,-1):
for k in range(1,s+1):
if v*k<=j:
m[j]=max(m[j],m[j-v*k]+w*k) #每次可以取多个
print(m[V]) #输出最大价值
方法一将通过条件语句将三种背包问题分开处理,同时对所有的背包问题使用同一个动态转移函数使它们的转台转移状态一致,解决该问题。但是该方法存在缺陷,主要是对于多背包问题的处理,时间复杂度要求较高,无法通过所有的测试案例。
方法二:
参考他人的思路写的求解方法,主要思路是将问题中的所有背包问题都转换成多背包问题。01背包问题,转换成出现次数为1的多背包问题;完全背包问题,用背包的总容量除以完全背包的体积,得到的结果设置为该背包出现的次数。最后使用二进制优化方法处理这个转化后的多背包问题。
原帖链接
n,m=map(int,input().split()) #输入n和m
v,w=[],[] #创建两个数组
f=[0 for i in range(100010)] #创建一个长度100010的数组并全部初始化为0
cnt=0
for i in range(1,n+1): #循环n遍
a,b,s=map(int,input().split()) #输入a,b,s
k=1
if s<0: #如果s小于0
s=1
elif s==0: #如果s等于0
s=m//a #s等于总体积除以a
while k<=s: #当k小于等于s时
v.append(a*k) #将a*k添加至v数组
w.append(b*k) #将b*k添加至w数组
s-=k #s减去k
k*=2 #k乘以2
cnt+=1 #cnt加1
if s>0: #如果s大于0
v.append(s*a) #将s*a添加至v数组
w.append(s*b) #将s*b添加至w数组
cnt+=1 #cnt加1
#将多重背包进行二进制优化,变成01背包
for i in range(1,cnt+1): #循环到cnt
for j in range(m,v[i-1]-1,-1): #倒序遍历m到v[i]
f[j]=max(f[j],f[j-v[i-1]]+w[i-1]) #f[j]等于f[j]和f[j-v[i]]+w[i]之间较大的值
#01背包问题
print(f[m]) #输出f[m]
方法二通过测试