思想解析:闫氏DP分析法,从此再也不怕DP问题!_哔哩哔哩_bilibili
题目以及解析来源:题库 - AcWing
推荐博客:dd大牛的《背包九讲》 - 贺佐安 - 博客园 (cnblogs.com)
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
解析:
/*
f[i][j]表示只看前i个物品,总体积是j的情况下,总价值最大是多少
f[i][j]:
1.不选第i个物品:f[i][j]=f[i-1][j]
2.选第i个物品:f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]) (当j>v[i]时)
*/
#include
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];
if(j>=v[i]){
f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
}
}
}
cout< 解析优化使用一维空间
01背包问题空间优化的原理是:
我们其实还是进行双重循环
#include
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=m;j>=v[i];j--){
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
cout< 有 N 件物品和一个容量是 V 的背包。每件物品可以无限用。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
解析:
/*
f[i][j]表示只看前i个物品,总体积是j的情况下,总价值最大是多少
f[i][j]:
1.不选第i个物品:f[i][j]=f[i-1][j]
2.选第i个物品:
f[i][j]=max(f[i-1][j], ..... ,f[i-1][j-k*v[i]]+k*w[i], ....) (当j>k*v[i]时)
f[i][j-v[i]]=max(f[i-1][j-v[i]], ..... ,f[i-1][j-k*v[i]]+(k-1)*w[i], ....) (当j>k*v[i]时)
两个公式相差值为w[i]
故f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);
*/
#include
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];
if(j>=v[i]){
f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
}
}
}
cout< 优化成一维空间
/*
f[i]表示总体积是i的情况下,总价值最大是多少
数学归纳法:
1.假设考虑前i-1个物品之后。所有的f[j]都是正确的
2.来证明:考虑完第i个物品后,所有的f[j]也都是正确的
队友某个j而言,如果最优解中包含k个v[i]
f[j-k*v[i]]
f[j-(k-1)*v[i]-v[i]]+w[i] 包含1个v[i]
...
f[j] f[j-v[i]]+w[i]
*/
#include
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i];
for(int j=v[i];j<=m;j++){
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
cout< 有 N 件物品和一个容量是 V 的背包。
第 i 件物品最多有si 件,体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,si用空格隔开,分别表示第 i 件物品的体积和价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
解析:
01背包的拓展
/*
f[i]总体积是i的情况下,最大价值是多少
1.f[i]=0
f[m]
2.f[0]=0,f[i]=-INF,i!=0
max{f[0 .... m]}
*/
#include
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N],s[N];
int f[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>w[i]>>s[i];
}
for(int i=1;i<=n;i++){
for(int j=m;j>=v[i];j--){
for(int k=1;k*v[i]<=j&&k<=s[i];k++){
f[j]=max(f[j],f[j-k*v[i]]+k*w[i]);
}
}
}
cout< 数据范围更改为:
0 0 0 提示:本题考查多重背包的二进制优化方法。 数据范围再更改 0 提示:本题考查多重背包的单调队列优化方法。 困难 类似题:力扣:239. 滑动窗口最大值 - 力扣(LeetCode) 有 N 种物品和一个容量是 V 的背包。 物品一共有三类: 每种体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输入格式 第一行两个整数,N,V用空格隔开,分别表示物品种数和背包容积。 接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。 输出格式 输出一个整数,表示最大价值。 数据范围 0 输入样例 输出样例: 解析: 有 N 件物品和一个容量是 V 的背包,背包能承受的最大重量是 M。 每件物品只能用一次。体积是 vi,重量是 mi,价值是 wi。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。 输入格式 第一行三个整数,N,V,M,用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。 接下来有 N行,每行三个整数 vi,mi,wi,用空格隔开,分别表示第 i 件物品的体积、重量和价值。 输出格式 输出一个整数,表示最大价值。 数据范围 0 输入样例 输出样例: 解析: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Fl4116Z-1663824406641)(D:\Desktop\背包九讲.assets\image-20220921183126088.png)] 有 N 组物品和一个容量是 V 的背包。 每组物品有若干个,同一组内的物品最多只能选一个。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 第一行有两个整数 N,V用空格隔开,分别表示物品组数和背包容量。 接下来有 N 组数据: 输出格式 输出一个整数,表示最大价值。 数据范围 0 输入样例 输出样例: 题解: 优化成一维空间 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出 最优选法的方案数。注意答案可能很大,请输出答案模 109+7 的结果。 输入格式 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。 输出格式 输出一个整数,表示 方案数 模 109+7的结果。 数据范围 0 输入样例 输出样例: 题解 有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。 第 ii 件物品的体积是 vivi,价值是 wiwi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是 1…N1…N。 输入格式 第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。 接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。 输出格式 输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。 物品编号范围是 1…N1…N。 数据范围 0 输入样例 输出样例: 题解: 困难 有 NN 个物品和一个容量是 VV 的背包。 物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。 如下图所示: 如果选择物品5,则必须选择物品1和2。这是因为2是5的父节点,1是2的父节点。 每件物品的编号是 ii,体积是 vivi,价值是 wiwi,依赖的父节点编号是 pipi。物品的下标范围是 1…N1…N。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 第一行有两个整数 N,VN,V,用空格隔开,分别表示物品个数和背包容量。 接下来有 NN 行数据,每行数据表示一个物品。 输出格式 输出一个整数,表示最大价值。 数据范围 1≤N,V≤1001≤N,V≤100 父节点编号范围: 输入样例 输出样例: 题解: dfs在遍历到 x 结点时,先考虑一定选上根节点 x ,因此初始化 f[ x] [v[x] ~ m] = w[x] 有依赖的背包问题是指物品之间存在依赖关系,这种依赖关系可以用一棵树来表示,要是我们想要选择子节点就必须连同其父节点一块选。/*
v,w 多数量物品拆成单一物品放到数组当中去
二进制拆法:
log(s)上取整
s - 1 - 2 - 4 - 8 直到为负数,将最后的s拿出来
*/
#include/*
f[j] = f[j-v]+w, f[j-2*v]+2w, ... f[j-k*v]+w
f[j+v]=f[j]+w, f[j-v]+2*w
*/
#include四、混合背包问题
输出最大价值。
−1≤si≤10004 5
1 2 -1
2 4 1
3 4 0
4 5 2
8
#include 五、二维费用的背包问题
输出最大价值。4 5 6
1 2 3
2 4 4
3 4 5
4 5 6
8
#include 六、分组背包问题
每件物品的体积是 vij,价值是 wij,其中 i是组号,j是组内编号。i≤100
03 5
2
1 2
2 4
1
3 4
1
4 5
8
#include>v[i][j]>>w[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];
for(int k=0;k=v[i][k]) f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]);
}
}
}
cout<#include>v[j]>>w[j];
}
for(int j=m;j>=0;j--){
for(int k=0;k=v[k]) f[j]=max(f[j],f[j-v[k]]+w[k]);
}
}
}
cout<七、背包问题求方案数
4 5
1 2
2 4
3 4
4 6
2
#include 八、背包问题求最优的物品方案
4 5
1 2
2 4
3 4
4 6
1 4
#include 九、有依赖的背包问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T7RA3jKG-1663824406643)(https://www.acwing.com/media/article/image/2018/10/18/1_bb51ecbcd2-QQ%E5%9B%BE%E7%89%8720181018170337.png)]
第 ii 行有三个整数 vi,wi,pivi,wi,pi,用空格隔开,分别表示物品的体积、价值和依赖的物品编号。
如果 pi=−1pi=−1,表示根节点。 数据保证所有物品构成一棵树。
1≤vi,wi≤1001≤vi,wi≤1005 7
2 3 -1
2 2 1
3 5 1
4 7 2
3 6 2
11
在分组背包部分:
j 的范围 [ m , v[x] ] 小于v[x]则没有意义因为连根结点都放不下;
k 的范围 [ 0 , j-v[x] ],当大于j-v[x]时分给该子树的容量过多,剩余的容量连根节点的物品都放不下了;#include
我们可以把有依赖的背包问题看成是分组背包问题,每一个结点是看成是分组背包问题中的一个组,子节点的每一种选择我们都看作是组内的一种物品,因此我们可以通过分组背包的思想去写。
但它的难点在于如何去遍历子节点的每一种选择,即组内的物品,我们的做法是从叶子结点开始往根节点做,并使用数组表示的邻接表来存贮每个结点的父子关系。#include
JSD-2204-Vant-微服务-Spring Cloud-Day01
如何熟悉一个服务/业务
【精简改造版】大型多人在线游戏BrowserQuest服务器Golang框架解析(2)——服务端架构
js设计模式:原型模式
【TensorFlow Hub】:有 100 个预训练模型等你用
SQLServer统计监控SQL执行计划突变的方法
关于线段树基础
【笔记】Sturctured Streaming笔记总结(Python版)
杠铃策略,给你的“B计划”一个“阶层跃升”的机会