文章目录
题目描述
01背包
n,V = map(int,input().split())
#这里的I表示的是第几个商品,j表示的是物品所占的体积
dp = [[0]*(V+1) for i in range(n+1)]
# 这里一般都是从1开始,防止越界
for i in range(1,n+1):
w,v = map(int,input().split())
for j in range(V + 1):
#如果现在的书包容量装不下,那么就用前一个商品的状态去更新
if j < w:
dp[i][j] = dp[i -1][j]
else :
#用上一个物品的状态和现在加入了这一个物品的状态价值进行比较,选取最大的
dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w]+v)
print(dp[n][V])
完全背包
基本思想:
区别于01的地方是这里的商品数量是无限的
这样写的时间复杂度为O(NVV)
改进如下:
代码:
n,V = map(int,input().split())
#这里的I表示的是第几个商品,j表示的是物品所占的体积
dp = [[0]*(V+1) for i in range(n+1)]
# 这里一般都是从1开始,防止越界
for i in range(1,n+1):
w,v = map(int,input().split())
for j in range(V + 1):
#如果现在的书包容量装不下,那么就用前一个商品的状态去更新
if j < w:
dp[i][j] = dp[i -1][j]
else :
#用上一个物品的状态和现在加入了这一个物品的状态价值进行比较,选取最大的
dp[i][j] = max(dp[i - 1][j],dp[i][j - w]+v)
print(dp[n][V])
时间复杂度变为O(N*V)
这里可以用记忆化搜索(记录先前搜索的信息):
N,V = map(int,input().split())
dp = [0]*(V+1)
for i in range(1,N+1):
w,v = map(int,input().split())
for j in range(w,V+1):
dp[j] = max(dp[j],dp[j-w]+v)
print(dp[V])
多重背包
区别:
是01背包和完全背包的结合体,表示商品的数量是k个的(k大于等于1)
基础代码思路:
N,V = map(int,input().split())
#这里的I表示的是第几个商品,j表示的是物品所占的体积
dp = [[0]*(V+1) for i in range(N+1)]
# 这里一般都是从1开始,防止越界
for i in range(1,N+1):
w,v,s = map(int,input().split())
for j in range(V + 1):
# 这里必须保证j-k*w>=0
for k in range(min(s,j//w)+1):
dp[i][j] = max(dp[i][j], dp[i-1][j-k*w]+k*w)
print(dp[N][V])
数量变为Nlog(S),体积为V,时间复杂度为O(Nlog(S)V)
N, V = map(int, input().split())
new_w_v= []
for i in range(1,N+1):
w,v,s = map(int,input().split())
k = 1
while s >= k:
new_w_v.append((k*w,k*v))
s -= k
k *= 2
if s != 0:
new_w_v.append((s*w, s*v))
#01背包的代码
dp = [0]*(V+1)
for i,(w,v) in enumerate(new_w_v,1):
for j in range(V,w-1,-1):
dp[j] = max(dp[j],dp[j-w]+v)
print(dp[V])
单调队列优化多重背包
可以参考这篇详细的讲解:
https://blog.csdn.net/jisuanji2606414/article/details/123384333
N, V = map(int, input().split())
dp = [0]*(V+1)
for _ in range(N):
v, w, s = map(int, input().split())
for c in range(v):
queue = []
hh, tt = 0, -1
times = (V-c) // v
for k in range(times+1):
curr = dp[k*v+c] - k*w
print("k,curr",k,curr)
if hh <= tt and queue[hh][0] == k-s-1:
hh += 1
while hh <= tt and queue[-1][1] < curr:
queue.pop()
print("tt,hh", tt,hh )
tt -= 1
queue.append([k, curr])
tt += 1
dp[k*v+c] = queue[hh][1] + k*w
print(dp[V])
二维费用背包
题目和思路
N,V,M = map(int,input().split())
dp = [[0]*(M+1) for i in range(V+1)]
for i in range(N):
v,m,w = map(int,input().split())
#从后往前更新
for j in range(V,v-1,-1):
for k in range(M,m-1,-1):
dp[j][k] = max(dp[j][k],dp[j-v][k-m]+w)
print(dp[V][M])
分组背包
题目和思路
基本写法(耗费内存)
N,V = map(int,input().split())
dp = [[0]*(V+1) for i in range(N + 1)]
#对于每一组
for i in range(1,N+1):
each_group = []
s = int(input())
#对于每一组数组
for _ in range(s):
w,v = map(int,input().split())
for j in range(V+1):
if j < w:
#每组物品都要涉及更新dp[i][j],因此要max
dp[i][j] = max(dp[i][j],dp[i-1][j])
else:
dp[i][j] = max(dp[i][j],dp[i-1][j],dp[i-1][j-w]+v)
print(dp[N][V])
使用滚动数组
#使用滚动数组
N,V = map(int,input().split())
groups= []
for _ in range(N):
s = int(input())
each_group = [list(map(int,input().split())) for i in range(s)]
groups.append(each_group)
dp = [0] * (V+1)
#枚举每一组
for i in range(1,N+1):
#枚举每一个体积
for j in range(V,-1,-1):
#枚举第i组的每一件物品
for w,v in groups[i-1]:
if j >= w:
dp[j] = max(dp[j],dp[j-w]+v)
为什么数组要从大到小遍历
蓝桥云课学习笔记分享
持续更新中~ 2024蓝桥杯一起冲!
by 闻不多