Acwing动态规划1——背包问题
文章目录
- 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——背包问题相关推荐
- [AcWing] 9. 分组背包问题(C++实现)分组背包问题模板题
[AcWing] 9. 分组背包问题(C++实现)分组背包问题模板题 1. 题目 2. 读题(需要重点注意的东西) 3. 解法 4. 可能有帮助的前置习题 5. 所用到的数据结构与算法思想 6. 总结 ...
- Suzy心情很差因为被charge了late fee Day42 | 动态规划之背包问题,416. 分割等和子集
背包问题 01背包 Given n种物品,每种物品只有1个 每个物品有自己的重量.价值. 背包最大能装载的重量 动规五部曲--用二维数组 定义dp数组的含义:dp[ i ][ j ]表示[0,i]物品 ...
- 【AcWing】AcWing 2. 01背包问题
目录 一.题目 1.原题链接 2.题目描述 二.解题报告 1.思路分析 2.时间复杂度 3.代码详解 一.题目 1.原题链接 2. 01背包问题 - AcWing题库 2.题目描述 有 N 件物品和一 ...
- 【算法与数据结构】—— 动态规划之背包问题
动态规划之背包问题 前面介绍了一些最常见的动态规划题型和对应解法,而实际上,动态规划最经典的题型非背包问题莫属,并且大多数人最初都是从背包问题入坑进而打开动态规划这一大门. 背包问题分为多种,其中最常 ...
- 动态规划之背包问题的一些基础简单入门题
前言 参考视频教程洛谷试练场 普及组 动态规划的背包问题 主要有01背包问题.完全背包问题.分组背包问题. 01背包问题一般从右往左推: 完全背包问题一般从左往右推: 分组背包一般用01的方法但需要记 ...
- c语言背包问题装字母,C语言动态规划之背包问题详解
01背包问题 给定n种物品,和一个容量为C的背包,物品i的重量是w[i],其价值为v[i].问如何选择装入背包的物品,使得装入背包中的总价值最大?(面对每个武平,只能有选择拿取或者不拿两种选择,不能选 ...
- 动态规划之背包问题——01背包
算法相关数据结构总结: 序号 数据结构 文章 1 动态规划 动态规划之背包问题--01背包 动态规划之背包问题--完全背包 动态规划之打家劫舍系列问题 动态规划之股票买卖系列问题 动态规划之子序列问题 ...
- 动态规划之背包问题(JAVA)
背包问题之前的C语言版本已经将思路解析的差不多,虽然还有些许错误需要改正,但大体思路是正确的,需要的读者请参阅动态规划之背包问题(C语言) 背包问题本身就是典型的动态规划问题,所以这里只给出动态规划的 ...
- 【动态规划】背包问题(组合问题,从n个物品中选k个)
文章目录 模板题(背包九讲) 划分依据 经典例题 AcWing 2. 01背包问题 最后一个选还是不选 1.AcWing 423. 采药 2.AcWing 1024. 装箱问题 3.AcWing 42 ...
- 动态规划解决背包问题
动态规划解决背包问题 问题描述: (1)解法一: 解决思路:动态规划 状态索引范围:从1开始 价值数组,大小数组索引范围:从0开始 状态:F(i,j):前i个物品放入大小为j的背包中所获得的最大价值. ...
最新文章
- IDEA 在线翻译插件
- Windows 7 开发系列汇总
- 服务器控件调用JS方法
- kafka重置到最新offset偏移量
- How your face shapes your economic chances
- 拉新不留存,就是负增长(附建议)
- 是先打工还是直接创业?答案让我惊呆了!
- hdu 1241Oil Deposits(BFS)
- ubuntu系统debootstrap的使用(构建一套基本的系统)
- 用可视化报告拿到20W年终奖的时候,才知道数据可视化的重要
- pythonrequests证书_requests的ssl证书验证、身份认证、cert文件证书
- STM32神舟III号 驱动直流电机学习(四 )
- 使用MetaHuman Creator 塑造你心中的人物
- 计算机和小学科课题,《小学信息技术课堂有效教学的探索》课题研究方案
- 阿里云国际版查看云服务器ecs实例系统日志和截图-Unirech
- 有关Unity3D的OnRenderImage()和Blit()的一些问题
- 深信服校园招聘c/c++ 软件开发A卷--菜鸡落泪
- Intel(Altera)FPGA的SOF转JIC文件和下载详细教程
- Storm DRPC 使用及访问C++ Bolt问题的解决方法
- 亚马逊Facebook头条布局社交电商的焦虑