引言
背包问题可以分为:
- 01背包 (空间优化:倒序)
- 完全背包 (空间优化:正序)
- 多重背包及其优化(化为01背包,最低复杂度 O ( N Σ log 2 ( K ) ) O(N\Sigma \log_2(K)) O(NΣlog2(K)))
以及一些变种的问题:
- 分组背包
- 混合背包问题
- 二维费用背包问题
- 背包问题求方案数
- 背包问题求最优方案数
- 背包问题求具体的方案
- 有依赖的背包问题
- 大于某个限度的方案数量
01背包
有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
特点:每个物品的数量只有一个。
状态:dp[i][j]
考虑前 i 个物品,空间为 j
- 没有进行优化:第二层循环正序
dp[i][j] = max(dp[i-1][j], dp[i-1][j-vi]+wi)
- 进行优化:第二层倒序
dp[j] = max(dp[j], dp[j-vi]+wi)
## 未进行优化
n, v = map(int, input().split())
dp = [[0]*(v+1) for _ in range(n+1)]
for i in range(1, n+1):
a,b = map(int, input().split())
for j in range(1,v+1):
# 分别考虑,大于体积和不大于
if j>=a:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-a]+b)
else:
dp[i][j] = dp[i-1][j]
print(dp[n][v])
## 进行状态压缩的优化
n, v = map(int, input().split())
dp = [0]*(v+1)
for i in range(n):
a,b = map(int, input().split())
for j in range(v, a-1, -1):
dp[j] = max(dp[j], dp[j-a]+b)
print(dp[v])
完全背包
背包中每种物品的个数是无穷多的,可以重复拿。
需要考虑优化:
f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w , f[i-1,j-2*v]+2*w , f[i-1,j-3*v]+3*w , .....)
f[i , j-v]= max( f[i-1,j-v] , f[i-1,j-2*v] + w , f[i-1,j-2*v]+2*w , .....)
由上两式,可得出如下递推关系:
f[i][j]=max(f[i,j-v]+w , f[i-1][j])
- 未进行空间优化:
dp[i][j] = max(dp[i-1][j], dp[i][j-vi]+wi)
注意后一项是dp[i]
转移的。 - 进行空间优化:第二层正序,
dp[j] = max(dp[j], dp[j-vi]+wi)
n, v = map(int, input().split())
# 未进行状态压缩
dp = [[0]*(v+1) for _ in range(n+1)]
for i in range(1,n+1):
a, b = map(int, input().split())
for j in range(1, v+1):
if j >= a:
# 注意这里于01背包不同,这里是从DP[i][j-k]转移
dp[i][j] = max(dp[i-1][j], dp[i][j-a] + b)
else:
dp[i][j] = dp[i-1][j]
print(dp[n][v])
# 进行状态压缩
dp = [0]*(v+1)
for i in range(n):
a, b = map(int, input().split())
for j in range(a,v+1):
dp[j] = max(dp[j], dp[j-a]+b)
print(dp[v])
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] v = new int[n];
int[] w = new int[n];
for(int i