DP——背包问题
背包问题
N 件物品放入容量为 V 的背包,求最大的价值。
常见的背包问题分为:01背包问题,完全背包问题。
其中核心的问题还是 01背包问题,其余的背包问题都是基于01背包的变形。
AcWing 2. 01背包问题
有 N件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0 01背包 集合的划分,原则:选不选最后一个物品,分为两种 集合如何划分 很多的DP问题可以在空间上进一步的优化,即对原来的状态计算进行等价变形。 观察状态转移方程 当前层的状态永远只依赖于上一层的状态,因此我们可以用户一维的状态 f[j] 来表示之前同样的状态。 在第 i次循环之前,f[j]=f[i-1][j] 在第 i次循环之后,f[j]=f[i][j] 因此我们的状态转移方程变为了 f[j]=max{f[j], f[j-v[i]]+w[i]} 注意:由于我们要保证 f[j-v[i]] 就相当于原来的 f[i-1][j-v[i]] ,所以我们的第二层循环需要改为逆序。 有 N种物品和一个容量是 V 的背包,每种物品都有无限件可用。 第 ii 种物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 第一行两个整数N,V,用空格隔开,分别表示物品种数和背包容积。 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 ii 种物品的体积和价值。 输出一个整数,表示最大价值。 0 状态表示 f[i][j]: 状态计算: 选k个: 合并一下 f[i][j] = max(f[i-1][j] , f[i][j-v] + w); 有 N 种物品和一个容量是 V 的背包。 第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输入格式 接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。 输出格式 数据范围 状态表示 f[i][j]: 状态计算: 题目描述:多重背包问题II 第 ii 种物品最多有 si 件,每件体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输入格式 接下来有 N 行,每行两个整数 vi, wi,si 用空格隔开,分别表示第 i 件物品的体积和价值和数量。 输出格式 数据范围 输入样例 首先,我们不能用完全背包的优化思路来优化这个问题,因为每组的物品的个数都不一样,是不能像之前一样推导不优化递推关系的。 我们列举一下更新次序的内部关系: max无法做减法,所以不可以用完全背包方式优化。 二进制优化的方法 总结: 代码 题目描述 每组物品有若干个,同一组内的物品最多只能选一个。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 接下来有 N 组数据: 每组数据第一行有一个整数 Si,表示第 i 个物品组的物品数量; 输出格式 数据范围 状态表示:f[i][j] 状态计算:输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
优化一般就是优化状态转移方程
特点:每个物品仅能使用一次
重要变量&公式解释
f[i][j]:表示所有选法集合中,只从前i个物品中选,并且总体积≤j的选法的集合,它的值是这个集合中每一个选法的最大值.
状态转移方程
f[i][j] = max(f[i-1][j], f[i-1][j-v[i]]+w[i])
一般原则:不重不漏,不重不一定都要满足(一般求个数时要满足)
如何将现有的集合划分为更小的子集,使得所有子集都可以计算出来.普通代码
import sys,math
sys.setrecursionlimit(10**9)
from collections import defaultdict
IA = lambda: map(int,input().split())
IAS= lambda: map(str,input().split())
n,m=map(int,input().split())
v=[0 for i in range(0,n+1)]
w=[0 for i in range(0,n+1)]
dp=[[0 for i in range(0,m+1)] for i in range(0,n+1)]
for i in range(0,n):
v[i],w[i]=map(int,input().split())
for i in range(0,n):
for j in range(0,m+1):
dp[i][j]=dp[i-1][j]
if j>=v[i]:
dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i])
print(dp[n-1][m])
优化代码
f[i][j]=max{f[i-1][j], f[i-1][j-v[i]]+w[i]}
可以发现:import sys,math
sys.setrecursionlimit(10**9)
from collections import defaultdict
IA = lambda: map(int,input().split())
IAS= lambda: map(str,input().split())
n,m=map(int,input().split())
v=[0 for i in range(0,n+1)]
w=[0 for i in range(0,n+1)]
dp=[0 for i in range(0,m+1)]
for i in range(0,n):
v[i],w[i]=map(int,input().split())
for i in range(0,n):
for j in range(m,v[i]-1,-1):
dp[j]=max(dp[j],dp[j-v[i]]+w[i])
print(dp[m])
AcWing 3. 完全背包问题
输出最大价值。输入格式
输出格式
数据范围
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
基本代码
集合:所有满足只从前i个物品选,总体积不超过j的方案的集合。
属性:Max
集合划分
选0个,选1个,选2个,选3个,...,选k个,...,选无穷个。import sys,math
sys.setrecursionlimit(10**9)
from collections import defaultdict
IA = lambda: map(int,input().split())
IAS= lambda: map(str,input().split())
n,m=map(int,input().split())
v=[0 for i in range(0,n+1)]
w=[0 for i in range(0,n+1)]
dp=[[0 for i in range(0,m+1)] for i in range(0,n+1)]
for i in range(0,n):
v[i],w[i]=map(int,input().split())
for i in range(0,n):
for j in range(0,m+1):
dp[i][j]=dp[i-1][j]
if j>=v[i]:
dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+w[i])
print(dp[n-1][m])
优化代码
import sys,math
sys.setrecursionlimit(10**9)
from collections import defaultdict
IA = lambda: map(int,input().split())
IAS= lambda: map(str,input().split())
n,m=map(int,input().split())
v=[0 for i in range(0,n+1)]
w=[0 for i in range(0,n+1)]
dp=[0 for i in range(0,m+1)]
for i in range(0,n):
v[i],w[i]=map(int,input().split())
for i in range(0,n):
for j in range(v[i],m+1):
dp[j]=max(dp[j],dp[j-v[i]]+w[i])
print(dp[m])
AcWing 4. 多重背包问题 I
输出最大价值。
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
输出一个整数,表示最大价值。
0
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10题解
集合:所有满足只从前i个物品选,总体积不超过j的方案的集合。
属性:Max
集合划分
选0个,选1个,选2个,选3个,...,选k个,...,选s[i]个。#include
AcWing 5. 多重背包问题 II
有 N种物品和一个容量是 V 的背包,每种物品都有无限件可用。
输出最大价值。
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
输出一个整数,表示最大价值。
0
4 5
1 2
2 4
3 4
4 5
输出样例
10多重背包的优化
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-1][j-sv] + sw)
f[i , j-v]= max( f[i-1,j-v] , f[i-1,j-2*v] + w , f[i-1,j-3*v]+2*w , ...,,f[i-1][j-(s+1)v] + sw)
假设s = 1023(2^10-1)
我们可以用1,2,4,8,...,512 (2^9) 来组合成0~1023,枚举10次。
即\(2^0,2^1,.... ,2^k\)可以表示所有\(0 -2^{k+1}\)里面的数
给我们S个物品,我们可以拆分打包成logS物品,就变成01背包问题。
即\(1,2,4,8,...,2^k,C (C= S- sum(1,2^k)<2^{k+1})\)
拼成0~2^(k+1)#include
AcWing 9. 分组背包问题
有 N 组物品和一个容量是 V 的背包。
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。
第一行有两个整数 N,V,用空格隔开,分别表示物品组数和背包容量。
每组数据接下来有 Si 行,每行有两个整数 vij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值;
输出一个整数,表示最大价值。
0
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8
题目考点
动态规划解题思路
f[i][j] = max(f[i][j], f[i - 1][j - v[i][k]] + w[i][k]);代码
#include