01背包
先浅浅的占个位置,接下来的三天内补上
给定一个容积为V的背包,现在有N个物品,第i件物品的体积为wi,价值为vi。每件物品只能拿或者不拿,请求出体积总和不超过V的最大价值。
动态规划状态:dp[i][j]前i件物品,体积为j的最大价值。背包问题通用的用法
状态转移方程:
边界问题:dp[...][j] = 0, dp[...][0] = 0,直接在初始化时解决。
直接看一个模版题目:
在这里最困难的是状态转移方程,01背包的状态转移方程上面已经给出。代码比较简单,就不加注释了。
n, v = map(int, input().split())
dp = [[0] * (v + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
wi, vi = map(int,input().split())
for j in range(1, v + 1):
if j - wi >= 0:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - wi] + vi)
else:
dp[i][j] = dp[i - 1][j]
print(dp[n][v])
滚动数组优化:
上述的方程中,第i行的更新,仅和第i - 1行有关, 因此可以使用滚动数组优化 。
优化代码只需要在第一维对2取模即可。
n, v = map(int, input().split())
dp = [[0] * (v + 1) for _ in range(2)]
for i in range(1, n + 1):
wi, vi = map(int,input().split())
for j in range(1, v + 1):
if j - wi >= 0:
dp[i % 2][j] = max(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - wi] + vi)
else:
dp[i % 2][j] = dp[(i - 1) % 2][j]
print(dp[n % 2][v])
进一步的优化使用长度为1的滚动数组优化可空间:
通过观察可以发现:在更新当前dp[i][j]是需上一横行前面的值即可,因此只需要在第二层循环时反着来即可。(可能刚开始不好理解,可以画图,尝试理解一下)。
n, v = map(int, input().split())
dp = [0] * (v + 1)
for i in range(1, n + 1):
wi, vi = map(int, input().split())
# 在这里一定要反着更行,注意取值。
for j in range(v, wi - 1, -1):
dp[j] = max(dp[j], dp[j - wi] + vi)
print(dp[v])
刚开始做这个题时很蒙,不知道为什么,dp[j] = dp[j] + ei,没有限制条件 if ai > j: ,后来看dp[i][j]的含义的时候才发现问题所在,dp[i][j]:的含义是前i个人总共倒水为j。哎呀我描述不清楚,大家自行理解吧。
# dp[i][j]:表示前i个人的总共倒水为j
n, m = map(int, input().split())
dp = [0] * (m + 1)
for i in range(1, n + 1):
ai, bi, ci, di, ei = map(int, input().split())
# 题目中说倒水不足ai毫升(可以为0)注意:这个可以为0的条件。
for j in range(m, -1, -1):
# 在以下的条件中更新最大的dp[j]和01背包类似只是多了一部分的条件
dp[j] = dp[j] + ei
if j - ai >= 0:
dp[j] = max(dp[j], dp[j - ai] + bi)
if j - ci >= 0:
dp[j] = max(dp[j], dp[j - ci] + di)
print(dp[m])
import sys
n = int(input())
a = [int(input()) for _ in range(n)]
# m:表示宝物的总质量
m = sum(a)
# 将总质量分半
v = m // 2
dp = [0] * (v + 1)
if m & 1:
print('no')
sys.exit()
for i in range(n):
wi, vi = a[i], a[i]
for j in range(v, wi - 1, -1):
dp[j] = max(dp[j], dp[j - wi] + vi)
if dp[v] == v:
print('yes')
else:
print('no')
n = int(input())
# dp[i][j]:表示前i个课程,等待时间为j
dp = [0] * (int(1e5) + 10)
li = []
# 这里为什么排序我也有点蒙蒙的
for i in range(n):
li.append(list(map(int, input().split())))
li.sort(key=lambda x: (x[1]))
for i in range(0, n):
# a, b, c = map(int, input().split())
a, b, c = li[i][0], li[i][1], li[i][2]
# 对于这里要注意b,打折截止时间,如果截止就没有办法选课了。所以注意范围
for j in range(b, a - 1, -1):
dp[j] = max(dp[j], dp[j - a] + c)
print(max(dp))