文章目录

  • 1.0 1背包——每件物品最多只能用一次
  • 2.完全背包——每件物品可以用无限次
  • 3.多重背包——优化问题
  • 4.分组背包

常用模型:背包

背包模型 区别 状态方程
01背包 每件物品最多只能用一次 f[i][j] = max(f[i-1, j], f[i-1, j-v] + w)
完全背包 每件物品可以用无限次 f[i][j] = max(f[i-1, j], f[i, j-v] + w)
多重背包 优化问题
分组背包 n组物品,每组m种类型,只能从每组中选一个

1.0 1背包——每件物品最多只能用一次

问题:有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。

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

状态方程:f[i][j] = Math.max(f[i-1][j], f[i-1][j-v[i]] + w[i])

import java.io.IOException;
import java.util.Scanner;/*** @author mys* @date 2022/2/1 20:29* 01背包* 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。* 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大,输出最大价值。*/
public class p2_dp_01bag {static int N = 1010;public static void main(String[] args) throws IOException {int[] v = new int[N], w = new int[N];//v表示物品体积,w表示物品价值int[][] f = new int[N][N];//f表示状态 i物品个数 j背包容量Scanner sc = new Scanner(System.in);System.out.println("请输入物品个数和背包容量:");int n = sc.nextInt();n表示物品个数,m表示背包容量int m = sc.nextInt();//输入所有物品System.out.println("请输入所有物品体积和价值:");for (int i = 1; i <= n; i ++) {v[i] = sc.nextInt();w[i] = sc.nextInt();}//初始化时需要枚举所有状态f[0-n][0-m]//f[0][0-m] = 0:表示0件物品,其总体积不超过0-m,其最大价值是多少,默认为0,初始化时可以不写for (int i = 1; i <= n; i ++) {for (int j = 0; j <= m; j ++) {f[i][j] = f[i - 1][j];//不含i//包含i,注意判断情况,如果j<v[i]为空集,不满足条件if (j >= v[i]) {f[i][j] = Math.max(f[i][j], f[i-1][j-v[i]] + w[i]);//先去掉i情况,再加上i的价值}}}System.out.println(f[n][m]);}
}

滚动数组:每次都是用固定的几个存储空间,将二维数组转为一维数组,节省存储空间,达到优化的效果。滚动数组只适用于计算最终结果,而不需要存储中间结果的场景

将状态f [i] [j]编程一维f[i]进行优化

为什么一维情况下枚举背包容量需要逆序?

在二维情况下,状态f [i] [j]是由上一轮i - 1的状态得来的,f [i] [j]与f[i - 1] [j]是独立的。而优化到一维后,如果我们还是正序,则有f[较小体积]更新到f[较大体积],则有可能本应该用第i-1轮的状态却用的是第i轮的状态。

状态方程变为:f[j] = max(f[j], f[j - v[i]] + w[i]

最终代码:

import java.io.IOException;
import java.util.Scanner;/*** @author mys* @date 2022/2/1 20:29* 01背包* 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。* 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大,输出最大价值。*/
public class p2_dp_01bag2 {static int N = 1010;public static void main(String[] args) throws IOException {int[] v = new int[N], w = new int[N];//v表示物品体积,w表示物品价值int[] f = new int[N];//f表示状态 i物品个数 j背包容量Scanner sc = new Scanner(System.in);System.out.println("请输入物品个数和背包容量:");int n = sc.nextInt();n表示物品个数,m表示背包容量int m = sc.nextInt();//输入所有物品System.out.println("请输入所有物品体积和价值:");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 = m; j >= v[i]; j --) {f[j] = Math.max(f[j], f[j - v[i]] + w[i]);}}System.out.println(f[m]);}
}

2.完全背包——每件物品可以用无限次

问题:有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用,第 i 种物品的体积是 vi,价值是 wi。

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;/*** @author mys* @date 2022/2/18 17:18* 有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。* 第 i 种物品的体积是 vi,价值是 wi。* 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。** 输入:* 4 5* 1 2* 2 4* 3 4* 4 5* 输出:10*/
public class p3_dp_completeBag {static int N = 1010;public static void main(String[] args) throws IOException {int[] v = new int[N], w = new int[N];//v:体积 w:价值int[][] f = new int[N][N];//f:状态Scanner sc = new Scanner(System.in);//输入物品个数和背包数量int n = sc.nextInt();int m = sc.nextInt();//输入所有物品体积和价值for (int i = 1; i <= n; i ++) {v[i] = sc.nextInt();w[i] = sc.nextInt();}//完全背包状态方程 i物品个数 j背包容量for (int i = 1; i <= n; i ++) {for (int j = 0; j <= m; j ++) {//k * v[i] <= j:如果有k个物品i,保证这k个物品的体积小于背包容量for (int k = 0; k * v[i] <= j; k ++) {f[i][j] = Math.max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);}}}System.out.println(f[n][m]);}
}

优化问题

1、优化k层循环

优化后核心代码:

//完全背包
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] = Math.max(f[i][j], f[i][j - v[i]] + w[i]);}}
}
//对比01背包
for (int i = 1; i <= n; i ++) {for (int j = 0; j <= m; j ++) {f[i][j] = f[i - 1][j];//包含i//不包含i,注意判断情况,如果j<v[i]为空集,不满足条件if (j >= v[i]) {f[i][j] = Math.max(f[i][j], f[i-1][j-v[i]] + w[i]);//先去掉i情况,再加上i的价值}}}

2、二维转一维

优化后核心代码:

//完全背包
for (int i = 1; i <= n; i++) {for (int j = v[i]; j <= m; j++) {f[j] = Math.max(f[j], f[j - v[i]] + w[i]);}
}
//对比01背包
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]);}}

完全背包一维优化后与01背包非常相似

f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);//01背包f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);//完全背包问题

最终代码:

import java.io.IOException;
import java.util.Scanner;/*** @author mys* @date 2022/2/18 17:18* 优化 二维->一维*/
public class p3_dp_completeBag3 {static int N = 1010;public static void main(String[] args) throws IOException {int[] v = new int[N], w = new int[N];//v:体积 w:价值int[] f = new int[N];//f:状态Scanner sc = new Scanner(System.in);//输入物品个数和背包数量int n = sc.nextInt();int m = sc.nextInt();//输入所有物品体积和价值for (int i = 1; i <= n; i++) {v[i] = sc.nextInt();w[i] = sc.nextInt();}//完全背包状态方程 i物品个数 j背包容量for (int i = 1; i <= n; i++) {for (int j = v[i]; j <= m; j++) {f[j] = Math.max(f[j], f[j - v[i]] + w[i]);}}System.out.println(f[m]);}
}

3.多重背包——优化问题

问题:有 N 种物品和一个容量是 V 的背包,第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大,输出最大价值。

数据范围:

第一种:0<N,V≤1000<N,V≤100, 0<vi,wi,si≤100

第二种:

0<N≤10000<N≤1000
0<V≤20000<V≤2000
0<vi,wi,si≤2000


第一种:暴力解法

import java.util.Scanner;/*** @author mys* @date 2022/2/18 20:23* 有 N 种物品和一个容量是 V 的背包。* 第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。* 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。** 输入:4 51 2 32 4 13 4 34 5 2* 输出:10*/
public class p4_dp_multipleBag {public static int N = 110;public static void main(String[] args) {int[] v = new int[N], w = new int[N], s = new int[N];//体积 价值int[][] f = new int[N][N];//状态Scanner sc = new Scanner(System.in);int n = sc.nextInt();//物品个数int 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 = 0; j <= m; j ++) {for (int k = 0; k <= s[i] && k * v[i] <= j; k ++) {//朴素状态方程f[i][j] = Math.max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);}}}System.out.println(f[n][m]);}
}

第二种:二进制优化

最终代码:

import java.util.Scanner;public class p4_dp_multipleBag2 {//N >= 2000 * log2000 保险取值取25000  2000种物品,每种物品logS件public static int N = 25000, M = 2010;public static void main(String[] args) {int[] v = new int[N], w = new int[N];//体积 价值int[] f = new int[N];//状态Scanner sc = new Scanner(System.in);int n = sc.nextInt();//物品种数int m = sc.nextInt();//背包容量int count = 0;//存储新的物品for (int i = 1; i <= n; i ++) {//输入当前物品的信息int volume = sc.nextInt();//体积int value = sc.nextInt();//价值int s = sc.nextInt();//个数//一组二进制数:1 2 4 8 ... 2^k Cint k = 1;//从1开始凑和//用一组二进制数凑和,只要总和<=S就继续凑和,当总和要>S时就停止,最后如果有剩余用C来凑while (k <= s) {count ++;v[count] = volume * k;//k个物品的体积打包放一起w[count] = value * k;//k个物品的价值打包放一起s -= k;//S凑完之后减去k *= 2;//k变为下一个二进制数}//说明还剩下一些,相当于数组中的C 拼凑到一起补上if (s > 0) {count ++;v[count] = volume * s;w[count] = value * s;}}n = count;//更新nfor (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.println(f[m]);}
}

4.分组背包

n组物品,每组m种类型,只能从每组中选一个

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

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

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

输出最大价值。

输入格式

第一行有两个整数 N,VN,V,用空格隔开,分别表示物品组数和背包容量。

接下来有 NN 组数据:

  • 每组数据第一行有一个整数 Si,表示第 ii 个物品组的物品数量;
  • 每组数据接下来有 Si 行,每行有两个整数 vij,wijvij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值;

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V≤1000<N,V≤100
0<Si≤1000<Si≤100
0<vij,wij≤100

import java.util.Scanner;/*** @author mys* @date 2022/2/26 17:19** 输入:3 521 22 413 414 5* 输出:8*/
public class p5_dp_groupBag {static int N = 110;public static void main(String[] args) {int[][] v = new int[N][N], w = new int[N][N];//v体积 w价值int[] s = new int[N], f = new int[N];//s[i]:第i个物品的数量 f:状态Scanner sc = new Scanner(System.in);int n = sc.nextInt();//物品个数int m = sc.nextInt();//背包容量//输入物品信息for (int i = 1; i <= n; i ++) {s[i] = sc.nextInt();for (int j = 0; 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 >= 0; j --) {//背包容量for (int k = 0; k < s[i]; k ++) {//k个i物品if (v[i][k] <= j) {f[j] = Math.max(f[j], f[j - v[i][k]] + w[i][k]);}}}}System.out.println(f[m]);}}

2、线性DP

3、 区间DP

Acwing动态规划1——背包问题相关推荐

  1. [AcWing] 9. 分组背包问题(C++实现)分组背包问题模板题

    [AcWing] 9. 分组背包问题(C++实现)分组背包问题模板题 1. 题目 2. 读题(需要重点注意的东西) 3. 解法 4. 可能有帮助的前置习题 5. 所用到的数据结构与算法思想 6. 总结 ...

  2. Suzy心情很差因为被charge了late fee Day42 | 动态规划之背包问题,416. 分割等和子集

    背包问题 01背包 Given n种物品,每种物品只有1个 每个物品有自己的重量.价值. 背包最大能装载的重量 动规五部曲--用二维数组 定义dp数组的含义:dp[ i ][ j ]表示[0,i]物品 ...

  3. 【AcWing】AcWing 2. 01背包问题

    目录 一.题目 1.原题链接 2.题目描述 二.解题报告 1.思路分析 2.时间复杂度 3.代码详解 一.题目 1.原题链接 2. 01背包问题 - AcWing题库 2.题目描述 有 N 件物品和一 ...

  4. 【算法与数据结构】—— 动态规划之背包问题

    动态规划之背包问题 前面介绍了一些最常见的动态规划题型和对应解法,而实际上,动态规划最经典的题型非背包问题莫属,并且大多数人最初都是从背包问题入坑进而打开动态规划这一大门. 背包问题分为多种,其中最常 ...

  5. 动态规划之背包问题的一些基础简单入门题

    前言 参考视频教程洛谷试练场 普及组 动态规划的背包问题 主要有01背包问题.完全背包问题.分组背包问题. 01背包问题一般从右往左推: 完全背包问题一般从左往右推: 分组背包一般用01的方法但需要记 ...

  6. c语言背包问题装字母,C语言动态规划之背包问题详解

    01背包问题 给定n种物品,和一个容量为C的背包,物品i的重量是w[i],其价值为v[i].问如何选择装入背包的物品,使得装入背包中的总价值最大?(面对每个武平,只能有选择拿取或者不拿两种选择,不能选 ...

  7. 动态规划之背包问题——01背包

    算法相关数据结构总结: 序号 数据结构 文章 1 动态规划 动态规划之背包问题--01背包 动态规划之背包问题--完全背包 动态规划之打家劫舍系列问题 动态规划之股票买卖系列问题 动态规划之子序列问题 ...

  8. 动态规划之背包问题(JAVA)

    背包问题之前的C语言版本已经将思路解析的差不多,虽然还有些许错误需要改正,但大体思路是正确的,需要的读者请参阅动态规划之背包问题(C语言) 背包问题本身就是典型的动态规划问题,所以这里只给出动态规划的 ...

  9. 【动态规划】背包问题(组合问题,从n个物品中选k个)

    文章目录 模板题(背包九讲) 划分依据 经典例题 AcWing 2. 01背包问题 最后一个选还是不选 1.AcWing 423. 采药 2.AcWing 1024. 装箱问题 3.AcWing 42 ...

  10. 动态规划解决背包问题

    动态规划解决背包问题 问题描述: (1)解法一: 解决思路:动态规划 状态索引范围:从1开始 价值数组,大小数组索引范围:从0开始 状态:F(i,j):前i个物品放入大小为j的背包中所获得的最大价值. ...

最新文章

  1. IDEA 在线翻译插件
  2. Windows 7 开发系列汇总
  3. 服务器控件调用JS方法
  4. kafka重置到最新offset偏移量
  5. How your face shapes your economic chances
  6. 拉新不留存,就是负增长(附建议)
  7. 是先打工还是直接创业?答案让我惊呆了!
  8. hdu 1241Oil Deposits(BFS)
  9. ubuntu系统debootstrap的使用(构建一套基本的系统)
  10. 用可视化报告拿到20W年终奖的时候,才知道数据可视化的重要
  11. pythonrequests证书_requests的ssl证书验证、身份认证、cert文件证书
  12. STM32神舟III号 驱动直流电机学习(四 )
  13. 使用MetaHuman Creator 塑造你心中的人物
  14. 计算机和小学科课题,《小学信息技术课堂有效教学的探索》课题研究方案
  15. 阿里云国际版查看云服务器ecs实例系统日志和截图-Unirech
  16. 有关Unity3D的OnRenderImage()和Blit()的一些问题
  17. 深信服校园招聘c/c++ 软件开发A卷--菜鸡落泪
  18. Intel(Altera)FPGA的SOF转JIC文件和下载详细教程
  19. Storm DRPC 使用及访问C++ Bolt问题的解决方法
  20. 亚马逊Facebook头条布局社交电商的焦虑

热门文章

  1. 为什么JAVA对象需要实现序列化?
  2. Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务问题解决
  3. 【Windows】电脑清理个人隐私数据信息
  4. 英语发音规则之26个字母发音规则(A字母)
  5. My Twelfth Page - 环形链表Ⅱ - By Nicolas
  6. 看电影学英语是学习口语的最佳方式
  7. 康师傅被“水和面”糊住了眼睛?
  8. Html+Css+Js轮播图实现
  9. UNIX/Linux的传奇历史
  10. 案例——蚂蚁金服初探,唯一的金融互联网生态...