【蓝桥杯集训25】背包DP(5 / 7)
创始人
2025-05-31 11:32:40
0

目录

01背包板子

完全背包板子

多重背包板子

分组背包板子

2. 01背包问题 - 每种物品只有一件,体积至多j,总价值最大

1、二维dp 

2、一维dp

3. 完全背包问题 - 每种物品无限件,体积至多j,总价值最大

1、二维dp 

2、一维dp

4. 多重背包问题 I - 每种物品数量有限件,体积至多j,总价值最大

1、二维dp

2、一维dp

2、二进制优化版

9. 分组背包问题 - 每组物品最多选1个,体积至多j,总价值最大

1、一维dp

3382. 整数拆分 - 完全背包dp


01背包板子

01背包——要的是第i-1层状态,倒序遍历[m,v]

import java.util.*;class Main
{static int N=1010;static int[] f=new int[N];//f[j] N件物品,总体积不超过j的情况下,最大价值public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();f[0]=0;for(int i=1;i<=n;i++){int v=sc.nextInt(),w=sc.nextInt();for(int j=m;j>=v;j--)f[j]=Math.max(f[j],f[j-v]+w); //max(不选,选)}System.out.print(f[m]);}
}

完全背包板子

完全背包——要的是第i层状态,正序遍历[v,m]

import java.util.*;class Main
{static int N=1010;static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){int v=sc.nextInt(),w=sc.nextInt();for(int j=v;j<=m;j++)f[j]=Math.max(f[j],f[j-v]+w);}System.out.print(f[m]);}
}

多重背包板子

多重背包——要的是第i-1层,倒序遍历[m,1]注意判断j>=k*v

import java.util.*;class Main
{static int N=110;static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){int v=sc.nextInt(),w=sc.nextInt(),s=sc.nextInt();for(int j=m;j>=1;j--)for(int k=0;k<=s;k++)if(j>=k*v) f[j]=Math.max(f[j],f[j-k*v]+k*w);}System.out.print(f[m]);}
}

二进制优化版——将n个物品按二进制数装箱,每次取一个箱子的量,转化成01背包问题 

import java.util.*;class Main
{static int N=250000;static int[] v=new int[N],w=new int[N];static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();int cnt=0;for(int i=1;i<=n;i++) {int vv=sc.nextInt(),ww=sc.nextInt(),s=sc.nextInt();//对每一种物品i进行装箱for(int k=1;k<=s;k*=2){cnt++;v[cnt]=vv*k; w[cnt]=ww*k;s-=k;}if(s>0){cnt++;v[cnt]=vv*s;w[cnt]=ww*s;}}n=cnt;for(int i=1;i<=n;i++) //每次选一个箱子for(int j=m;j>=v[i];j--)f[j]=Math.max(f[j],f[j-v[i]]+w[i]);System.out.print(f[m]);}
}

分组背包板子

分组背包——要的是第i-1层,倒序遍历[m,1] 注意判断j>=v[i][k]

import java.util.*;class Main
{static int N=110;static int[][] v=new int[N][N];static int[][] w=new int[N][N];static int[] s=new int[N];static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){s[i]=sc.nextInt();for(int j=1;j<=s[i];j++){v[i][j]=sc.nextInt();w[i][j]=sc.nextInt();}}for(int i=1;i<=n;i++)for(int j=m;j>=1;j--)for(int k=1;k<=s[i];k++)if(j>=v[i][k])f[j]=Math.max(f[j],f[j-v[i][k]]+w[i][k]);System.out.print(f[m]);}
}

 


2. 01背包问题 - 每种物品只有一件,体积至多j,总价值最大

2. 01背包问题 - AcWing题库

题目:

N 件物品和一个容量是 V 的背包。每件物品只能使用一次

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大
输出最大价值。

1、二维dp 

思路:

  • 设f[i][j]:前i件物品,总体积不超过j的最大总价值
  • 答案即f[n][m]

注:当前的状态依赖于之前的状态,可以理解为从初始状态开始决策,有 N 件物品,则需要 N 次决策,每一次对第 i 件物品的决策,状态f[i][j]不断由之前的状态更新而来

  • 若j
  • 若j≥v[i],当前背包容量够,需要决策选or不选第i个物品
  1. 选:f[i][j]=f[i-1][j-v[i]]+w[i](前i-1个物品且体积给第i件物体留个空+第i件物品的价值)
  2. 不选:f[i][j]=f[i-1][j]
  3. 最后f[i][j]=max(选,不选)
import java.util.*;class Main
{static int N=1010;static int[] v=new int[N],w=new int[N];static int[][] f=new int[N][N];//f[i][j] 只选前i件物品,总体积不超过j的情况下,最大价值public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){v[i]=sc.nextInt();w[i]=sc.nextInt();}f[0][0]=0;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(j

2、一维dp

思路:

可以看出f[i][~]只依赖于f[i-1][~],所以根本没必要保留之前的f[i-2][~]等状态值

  • f[j]: N 件物品,背包容量j情况下的最大价值

要获得第i-1轮的状态,需要逆序  大的先更新,小的再更新

  • 更新索引值较大的dp值时,需要上一层“未被更新”的索引值较小的dp值
  • 在二维情况下,状态f[i][j]是由上一轮i - 1的状态得来的,而优化到一维后,如果我们还是从小到大顺序,则较小值先更新,则有可能本应该用第i-1轮的状态却用的是第i轮的状态
  • 因此要保证先更新大的,后更新小的,这才是第i-1轮状态,j应该从大到小循环
import java.util.*;class Main
{static int N=1010;static int[] f=new int[N];//f[j] N件物品,总体积不超过j的情况下,最大价值public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();f[0]=0;for(int i=1;i<=n;i++){int v=sc.nextInt(),w=sc.nextInt();for(int j=m;j>=v;j--)f[j]=Math.max(f[j],f[j-v]+w);}System.out.print(f[m]);}
}

3. 完全背包问题 - 每种物品无限件,体积至多j,总价值最大

3. 完全背包问题 - AcWing题库

题目:

N 种物品和一个容量是 V 的背包,每种物品都有无限件可用

第 i 种物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大
输出最大价值。

1、二维dp 

思路:

  • 设f[i][j]:前i件物品,总体积不超过j的最大总价值
  • 答案即f[n][m]

  • 选0件第i个物品:f[i][j]=f[i-1][j]
  • 选1件第i个物品:f[i][j]=f[i-1][j-v]+w
  • 选2件第i个物品:f[i][j]=f[i-1][j-2v]+2w
  • ……
  • 选k件第i个物品:f[i][j]=f[i-1][j-kv]+kw

因此 f[i][j]=max(f[i-1][j],f[i-1][j-v]+w,……,f[i-1][j-kv]+kw)

由于上述动态方程存在i,j,k三重循环,则会TLE,所以需要优化

f[i][j]=max(f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w……,f[i-1][j-kv]+kw)

将j用j-v替换得:

f[i][j-v]=max(f[i-1][j-v],f[i-1][j-2v]+w,……,f[i-1][j-(k+1)v]+kw)

则可推导:

f[i][j]=max(f[i-1][j],f[i][j-v]+w)

import java.util.*;class Main
{static int N=1010;static int[] v=new int[N],w=new int[N];static int[][] f=new int[N][N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){v[i]=sc.nextInt();w[i]=sc.nextInt();}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(j

2、一维dp

思路:

可以看出f[i][~]只依赖于f[i-1][~],所以根本没必要保留之前的f[i-2][~]等状态值

  • f[j]: N 件物品,背包容量j情况下的最大价值

要获得第i轮的状态,需要正序  小的先更新,大的再更新

import java.util.*;class Main
{static int N=1010;static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){int v=sc.nextInt(),w=sc.nextInt();for(int j=v;j<=m;j++)f[j]=Math.max(f[j],f[j-v]+w);}System.out.print(f[m]);}
}

4. 多重背包问题 I - 每种物品数量有限件,体积至多j,总价值最大

4. 多重背包问题 I - AcWing题库

题目:

 N 种物品和一个容量是 V 的背包。

第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大
输出最大价值。

1、二维dp

思路:

  • 设f[i][j]:前i件物品,总体积不超过j的最大总价值
  • 答案即f[n][m]

  • 选0件第i个物品:f[i][j]=f[i-1][j]
  • 选1件第i个物品:f[i][j]=f[i-1][j-v]+w
  • 选2件第i个物品:f[i][j]=f[i-1][j-2v]+2w
  • ……
  • 选s件第i个物品:f[i][j]=f[i-1][j-sv]+sw
import java.util.*;class Main
{static int N=110;static int[] v=new int[N],w=new int[N],s=new int[N];static int[][] f=new int[N][N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++) {v[i]=sc.nextInt();w[i]=sc.nextInt();s[i]=sc.nextInt();}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)for(int k=0;k<=s[i];k++)if(j>=k*v[i]) f[i][j]=Math.max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);//当k=0时,f[i-1][j-v[i]*k]+w[i]*k就是f[i-1][j]System.out.print(f[n][m]);}
}

2、一维dp

思路:

可以看出f[i][~]只依赖于f[i-1][~],所以根本没必要保留之前的f[i-2][~]等状态值

  • f[j]: N 件物品,背包容量j情况下的最大价值

要获得第i-1轮的状态,需要逆序  大的先更新,小的再更新

import java.util.*;class Main
{static int N=110;static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){int v=sc.nextInt(),w=sc.nextInt(),s=sc.nextInt();for(int j=m;j>=1;j--)for(int k=0;k<=s;k++)if(j>=k*v) f[j]=Math.max(f[j],f[j-k*v]+k*w);}System.out.print(f[m]);}
}

2、二进制优化版

5. 多重背包问题 II - AcWing题库 

思路:

  • 多重背包无法像完全背包那样用类似“错位相减”的方法优化,因此我们考虑问题转化:
  • 水果店里有 40 个苹果,小明计划购买 n   ( 1 ≤ n ≤ 40 )  个苹果,试问如何让小明尽可能快速地完成购买?一个显而易见的暴力做法是,让小明一个个拿(单位是个),但效率过于低下。事实上,店员可事先准备好 6 个箱子,每个箱子中的苹果数量分别为 [1,2,4,8,16,9],再让小明按箱子拿(单位是箱子),无论小明计划购买多少个,他最多只需要拿 6  次,而在暴力做法中,小明最多需要拿 40 次。

  • 在暴力求解多重背包问题时,对于每种物品i,都要从0开始枚举到s[i],效率低
  • 现在对于每种物品i,将这s[i]个物体分到 ⌊ log2s[i] ⌋+1个箱子里
  • 相当于转化成每次取一个箱子的量,也就是01背包问题
  • 也就是将s[i]拆分成若干个二进制的数的组合
  • 原本结果数为NVS=4×10^9
  • 优化后为NVlog2S=24000
import java.util.*;class Main
{static int N=250000;static int[] v=new int[N],w=new int[N];static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();int cnt=0;for(int i=1;i<=n;i++) {int vv=sc.nextInt(),ww=sc.nextInt(),s=sc.nextInt();//对每一种物品i进行装箱for(int k=1;k<=s;k*=2){cnt++;v[cnt]=vv*k; w[cnt]=ww*k;s-=k;}if(s>0){cnt++;v[cnt]=vv*s;w[cnt]=ww*s;}}n=cnt;for(int i=1;i<=n;i++) //每次选一个箱子for(int j=m;j>=v[i];j--)f[j]=Math.max(f[j],f[j-v[i]]+w[i]);System.out.print(f[m]);}
}

 

9. 分组背包问题 - 每组物品最多选1个,体积至多j,总价值最大

9. 分组背包问题 - AcWing题库

题目:

有 N 组物品和一个容量是 V 的背包。

每组物品有若干个,同一组内的物品最多只能选一个
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大

输出最大价值。

1、一维dp

思路:

  • 设f[j]:前N件物品,总体积不超过j的最大总价值
  • 答案即f[m]

对于二维dp进行分析,三重循环会超时:

  • 不选第i组的物品:f[i][j]=f[i][j]
  • 选第i组第1个物品:f[i][j]=f[i-1][j-v[i][1]]+w[i][1]
  • 选第i组第2个物品:f[i][j]=f[i-1][j-v[i][2]]+w[i][2]
  • ……
  • 选第i组第s个物品:f[i][j]=f[i-1][j-v[i][s]]+w[i][s]

 

要获得第i-1轮的状态,需要逆序  大的先更新,小的再更新

f[j]=max(f[j],f[j-v[i][k]]+w[i][k])

import java.util.*;class Main
{static int N=110;static int[][] v=new int[N][N];static int[][] w=new int[N][N];static int[] s=new int[N];static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt(),m=sc.nextInt();for(int i=1;i<=n;i++){s[i]=sc.nextInt();for(int j=1;j<=s[i];j++){v[i][j]=sc.nextInt();w[i][j]=sc.nextInt();}}for(int i=1;i<=n;i++)for(int j=m;j>=1;j--)for(int k=1;k<=s[i];k++)if(j>=v[i][k])f[j]=Math.max(f[j],f[j-v[i][k]]+w[i][k]);System.out.print(f[m]);}
}

 

3382. 整数拆分 - 完全背包dp

3382. 整数拆分 - AcWing题库

题目:

思路:

可以将问题转化成:

有m种物品(2的幂的种数),容量为n的背包,某种物品可以选无限个,问不超过容量n的最大方案数

也就是完全背包问题,定义f[j]为用2的幂凑出的值不超过j的最大方案数,则f[n]即是答案

import java.util.*;class Main
{static int N=1000010,mod=1000000000;static int[] f=new int[N];public static void main(String[] args){Scanner sc=new Scanner(System.in);int n=sc.nextInt();//定义f[j]用2的幂凑出的值不超过j的最大方案数f[0]=1;for(int i=1;i<=n;i*=2) //枚举2的幂数for(int j=i;j<=n;j++)f[j]=(f[j]+f[j-i])%mod;System.out.print(f[n]);}
}

 

相关内容

热门资讯

接口请求安全措施 一、敏感参数加密 一般情况下,我们针对一些敏感的参数,例如密码、身份证号...
性能测试Loaderrunne... 目录 一、性能测试概念 1.1为什么进行性能测试: 1.2系统性能测试流程 1.3如何...
vue3后台管理系统 后面可参考下:vue系列(三)——手把手教你搭建一个vue...
C++附加---静态库和动态库... 一、静态库的概念 ①概念:静态库是指在我们的应用中,有一些公共代码是需要...
草四字词语 关于草四字词语  碧绿的草地上,嫩嫩的小草亲密地挤在一起,拉着手儿,织出一块块柔软的地毯。小编整理的...
“能诗会赋”的意思 “能诗会赋”的意思 成语拼音: [néng shī huì fù] ...
“酒囊饭袋”的意思 “酒囊饭袋”的意思 成语拼音: [jiǔ náng fàn dài] ...
泰山梁木成语解析 泰山梁木成语解析  【成语】:泰山梁木  【拼音】:tài shān liáng mù  【简拼】:...
Docker: 容器如何访问w... 一、使用背景: 1、项目中使用到srs作为流媒体服务器 2、测试阶段时,...
优化软件测试成本,7个步骤简单... 【图源CSDN】软件测试可以防止那些修复起来成本很高的错误,从而避免将来因为它们所导致...
“秀水明山”的意思 “秀水明山”的意思 成语拼音: [xiù shuǐ míng shān] ...
地无遗利成语解释 地无遗利成语解释  成语是汉语词汇中定型的词。下面是小编整理的.地无遗利成语解释,希望对大家有所帮助...
“从头到尾”的意思 “从头到尾”的意思 成语拼音: [cóng tóu dào wěi] ...
“不足挂齿”的意思 “不足挂齿”的意思 成语拼音: [bù zú guà chǐ] ...
一文教会你Jenkins 主从... 目录 背景 添加Slave节点 连接Slave节点 Jenkins任务配置Slave节点执行 可能...
大文件上传 上图就是大致的流程一、标题图片上传课程的标题图片Ajax发送请求到后端后端接收到图片使用IO流去保存...
同样是软件测试岗位,年薪只比我... 相信大家听过网上流传的一句话: 35岁前当经理,35岁后开滴滴。 疫情当...
Springboot+vue开... 前言图书借阅管理系统项目是基于SpringBoot+Vue技术开发而来,功能相...
谈谈你的GC调优思路 第28讲 | 谈谈你的GC调优思路? 我发现,目前不少外部资料对 G1 的介绍大多还...
“百废俱举”的意思 “百废俱举”的意思 成语拼音: [bǎi fèi jù jǔ] ...