【动态规划】01背包问题

article/2025/10/3 2:25:27

👨‍🎓作者简介:一位喜欢写作,计科专业大二菜鸟

🏡个人主页:starry陆离

🕒首发日期:2022年5月16日星期一

🌌上期文章:【动态规划】最长上升子序列

📚订阅专栏:算法分析与设计
如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦

在这里插入图片描述

【背包问题】01背包问题

  • 1. 问题描述
  • 2. 问题分析
    • 2.1 减少规模
    • 2.2 推导递归式
  • 3 填DP表
  • 4 图解算法
  • 5 代码实现
  • 6. 构造最优解
  • 7. 练习题
  • 8. 扩展:空间压缩


1. 问题描述

给定n种物品(每种物品只有一件)和一个背包:物品i的重量是wi,其价值 为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物 品的总价值最大?

对于每种物品,只有两种选择:装(1)或者不装(0),不允许装物品的一部分

因此有这么一个著名的公式:

找出物品选择的组合的重量总和要不大于背包的容量为C,且要找出这些组合中装入背包中物品的总价值的最大的组合

image-20220514180709413

2. 问题分析

如果穷举这些组合,我们知道每一个物品都有选和不选,则一共有2 n(n是物品的种类);然后去除这些组合中大于背包的容量为C的组合,再找总价值最大的即为解;显然这个数量级太大了

2.1 减少规模

定义m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值

m(i+1,j)为可选择物品为i+1,…,n时0-1背包问题的最优值

。。。依次类推

m(n,j)为可选择物品为n时0-1背包问题的最优值,此时,规模已为1

即当可选物品为n时,背包容量为j,如果此时的背包容量能装下第n个物品,那么m(n,j)的最优值就是第n个物品的价值vn,装不下那就是0;(因为现在的可选物品只有第n个)

image-20220514181545409

2.2 推导递归式

判断是否放入第i件?

1)不放,背包当前产生价值仍为m(i+1,j)

2)放入,调整背包容量j-wi,背包当前产生价值为m(i+1, j-wi)+vi

结合两式即可得:

image-20220514202617064

3 填DP表

已知n=5, c=10, w={2, 2, 6, 5, 4}, v={6, 3, 5, 4, 6}

绘制m[i,j]的最下面两行

思路:

  • 由上面的分析可知,我们是从下往上,从左往右填dp表,

  • 如m(5,10)就是表示背包容量为10时,可选择物品为n时的最优值,而我们最终的解就是m(1,10)的值

  • 首先由第一个公式填最后一行m(5,j)(0<=j<10)

  • 然后有第二个公式填剩下的表格

4 图解算法

幻灯片1

幻灯片2

幻灯片3

幻灯片4

幻灯片5

​ 剩下的两行也是用同样的方法递推,读者可自己完成,理解这个逻辑过程

幻灯片6

5 代码实现

时间复杂度:O(nc)(n是物品种类,c是背包容量)

空间复杂度:S(nc)

private static int DpSolve(int n, int c, int[] w, int[] v, int[][] dp) {//初始化第n行for(int j=0;j<=c;++j) {if(j>=w[n]) {//System.out.println("w[n]="+w[n]);dp[n][j]=v[n];}}//动态规划for(int i=n-1;i>=1;i--) {for(int j=1;j<=c;++j) {if(j<w[i]) {dp[i][j]=dp[i+1][j];}else {dp[i][j]=Math.max(dp[i+1][j], dp[i+1][j-w[i]]+v[i]);}}}return dp[1][c];}

6. 构造最优解

能够求出01背包问题的最优值,我们如何求出一个最优解呢?

如上面的问题的最优解为1-》2-》5,如果用1代表选择物品,0代表不选择,那么结果可表示为11001

这个结果是如何得出的呢?

  1. 只需要当前的m(i,j)和它的下面的最优值m(i+1,j)比较,
    • 如果两者相等说明没有选择物品i,因为价值没有增加
    • 如果两者不相等说明选择了物品i,则需要把当前的背包容量j减去物品i的重量w(i),得出m(i+1,j-w(i)),其意义在于找到装入物品i前的背包能取得的最优值;
  2. 同理依次类推,循环执行第一步,直到找到倒数第二个物品是否选择
  3. 最后一步单独判断最后一个物品有没有选择,如果m(n,j)==0则表示没选择最后一个,不为0说明选择了

如上面的问题的最优解为1-》2-》5,如果用1代表选择物品,0代表不选择,那么结果可表示为11001

幻灯片7

只需要当前的m(i,j)和它的下面的最优值m(i+1,j)比较,

  • 如果两者相等说明没有选择物品i,因为价值没有增加;

  • 如果两者不相等说明选择了物品i,则需要把当前的背包容量j减去物品i的重量w(i),得出m(i+1,j-w(i)),其意义在于找到装入物品i前的背包能取得的最优值;

幻灯片8

​ 同理依次类推,循环执行第一步,直到找到倒数第二个物品是否选择

幻灯片9

幻灯片10

​ 最后一步单独判断最后一个物品有没有选择,如果m(n,j)==0则表示没选择最后一个,不为0说明选择了

幻灯片11

private static void Gouzao(int n, int c, int[] w, int[] v, int[][] dp) {for(int i=1;i<n;++i) {if(dp[i][c]==dp[i+1][c]) {//相等说明没选,输出0System.out.print("0");}else {//不相等说明选择了,输出1System.out.print("1");//更新背包的容量,要减去第i个物品的重量//准备去找装入物品i前的背包能取得的最优值c=c-w[i];}}//处理最后一个物品int last=(dp[n][c]>0?1:0);System.out.println(last);}

7. 练习题

原题地址:https://acm.hnucm.edu.cn/JudgeOnline/

题目描述

给定n种物品和一个背包,物品i的重量是Wi,其价值为Vi,背包的容量为C。如何选择装入背包的物品,可以使得装入背包中物品的总价值最大?

输入

每组输入包括三行,
第一行包括物品个数n,以及背包容量C。
第二、三行包括两个一维数组,分别为每一种物品的价值和重量。

输出

输出包括两行,第一行为背包的最大总价值,第二行为所选取的物品。
例如:最大总价值=15,物品选取策略为11001。数据保证答案唯一。

样例输入

5 10
6 3 5 4 6
2 2 6 5 4

样例输出

15
11001

import java.util.Scanner;
public class Main {public static void main(String[] args) {Scanner scanner=new Scanner(System.in);int n;int c;int[] w,v;int[][] dp;while(scanner.hasNext()) {n=scanner.nextInt();c=scanner.nextInt();w=new int[n+1];v=new int[n+1];dp=new int[n+1][c+1];for(int i=1;i<=n;++i) {v[i]=scanner.nextInt();}for(int i=1;i<=n;++i) {w[i]=scanner.nextInt();}for(int j=0;j<=c;++j) {if(j>=w[n]) {dp[n][j]=v[n];}}//动态规划for(int i=n-1;i>=1;i--) {for(int j=1;j<=c;++j) {if(j<w[i]) {dp[i][j]=dp[i+1][j];}else {dp[i][j]=Math.max(dp[i+1][j], dp[i+1][j-w[i]]+v[i]);}}}int ans=dp[1][c];		System.out.println(ans);	Gouzao(n,c,w,v,dp);}}private static void Gouzao(int n, int c, int[] w, int[] v, int[][] dp) {for(int i=1;i<n;++i) {if(dp[i][c]==dp[i+1][c]) {System.out.print("0");}else {System.out.print("1");c=c-w[i];}}int last=(dp[n][c]>0?1:0);System.out.println(last);}
}

8. 扩展:空间压缩

我们注意到每次递推第i行都是用下面一行(第i+1行)的最优值,如果只用一个一维数组dp[]来存储这些值,那么

递推第i行前,dp[i]=m(i+1,j)

递推第i行后,dp[i]=m(i,j)(覆盖掉原来的值)

而在计算递推第i行时的m()数组的值,有两种选择变化:

1)不放,背包当前产生价值仍为m(i+1,j),即dp[i]保持不变

2)放入,调整背包容量j-wi,背包当前产生价值为m(i+1, j-wi)+vi,即dp[j]=dp[j-wi]+vi

但是求解dp[]数组时,必须保证dp[j-wi]还是m(i,j-wi)的值,考虑到每次递推都会覆盖掉原来dp[]数组中的值,如当j的值从小往大变化,即我们从左往右求解时dp[j-wi]已经是m(i+1,j-wi)的值了;(读者可自行推演,如果这样上一题的答案会是30)

因而我们得从右往左求解,即j从大往下变化

image-20220514202617064

//动态规划
for(int i=n;i>=1;i--) {//j从大往下变化,保证dp[j-wi]还是m(i,j-wi)的值for(int j=c;j>=0;--j) {if(j>=w[i]) {dp[j]=Math.max(dp[j], dp[j-w[i]]+v[i]);}}
}

http://chatgpt.dhexx.cn/article/LCcvXuv0.shtml

相关文章

01背包问题:图表法带你快速理解动态规划解决01背包问题 附C++源码

0-1背包问题 所谓0-1背包问题&#xff0c;也就是给你一个重量为M的背包和n种物品&#xff0c;每种物品有一定的重量和价值&#xff0c;在每种物品均可装入背包1次或不装入&#xff08;不能仅装入物品的一部分&#xff09;且不超过背包载重量的前提下&#xff0c;问你怎样选择物…

动态规划——0/1背包问题(全网最细+图文解析)

✨动态规划——0/1背包问题(全网最细图文解析) 作者介绍: &#x1f393;作者:青花瓷✨ &#x1f440;作者的Gitee:代码仓库 &#x1f4cc;系列文章推荐: ✨1.数据结构与算法—算法篇之动态规划(一) ✨2.【Java刷题特辑第一章】——【点进来花两把游戏的时间学习晚上睡觉都踏实了…

【动态规划】01背包问题(通俗易懂,超基础讲解)

问题描述 有n个物品&#xff0c;它们有各自的体积和价值&#xff0c;现有给定容量的背包&#xff0c;如何让背包里装入的物品具有最大的价值总和&#xff1f; 为方便讲解和理解&#xff0c;下面讲述的例子均先用具体的数字代入&#xff0c;即&#xff1a;eg&#xff1a;numbe…

java事务和分布式事务详解

目录 事务问题 1 Java事务的类型 2 spring事务实现源码分析 事务问题 面试经常会问到分布式锁、分布式事务、SOA 服务化、分布式系统等业务、架构的问题和解决方案&#xff0c;工作中接触的业务方面事关金融&#xff0c;也需要解决一些类似的业务问题&#xff0c;所以总结…

JAVA事务配置总结

JAVA事务配置总结 使用hibernate&#xff1a;1.本地事务动态数据源单sessionFactory 这种情况属于大部分项目配置&#xff0c;在这里不多谈 2.全局事务动态数据源单sessionFactory 数据库分库分表时使用&#xff0c;已解决了不同库中相同名字的表相同ID的数据同时出现在同一…

Java事务回滚问题:抛出异常事务,并返回给前端异常信息

1、背景 修改bug。 之前的开发写的只能单选&#xff0c;所以逻辑都是按照只需要传递一个id值的逻辑写的 现在改为多选时&#xff0c;传递过来的是id数组&#xff0c;所以直接原逻辑的外层加了一个循环&#xff0c;这样原逻辑包括sql就不需要大变动&#xff0c; 但是这样会有个…

java事务中使用try catch 导致事务不回滚的问题

Transactional注解的触发&#xff0c;只回滚RuntimeException和Error异常&#xff0c;默认不回滚非RuntimeException异常 解决方法&#xff1a; 1.方法前添加注解&#xff08;基础的 Transactional注解&#xff1a;只能拦截RuntimeException和Error异常&#xff09; Transa…

java中事务

1.开启事务 事务的四大特性 ACID是原子性&#xff08;atomicity&#xff09;、一致性&#xff08;consistency&#xff09;、隔离性 &#xff08;isolation&#xff09;和持久性&#xff08;durability&#xff09;的缩写。 事务的原子性&#xff1a;事务作为整体执行&#x…

Java事务的ACID属性和四种隔离级别和传播机制

事务的ACID属性 数据库管理系统中事务(transaction)的四个特性&#xff08;分析时根据首字母缩写依次解释&#xff09;&#xff1a;原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;、持久性&a…

java回滚失败_java事务回滚失败问题分析

Spring-Java事物回滚失效处理最近在做项目中,无意间发现有个类在抛事物回滚操作,数据也正常的插入到数据库当中了,于是仔细查看看一下具体原因。 一切还是要从Java的检查型异常和非检查型异常说起。 那么什么是检查型异常什么又是非检查型异常呢? 最简单的判断点有两个: 1…

java中事务特性_java事务的四大特性ACID

前言 对于要把事务在实际中使用好&#xff0c;需要了解事务的特性。 事务的四大特性主要是&#xff1a;原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。 一、事务的四大特性 1.1原子性(Atomicity) 原子性是指事务是一个不可分割的工作单位&a…

Java 事务的传播性(Transactional)

前言 事务的传播性是Spring特有的概念&#xff0c;是基于Spring AOP技术实现的&#xff0c;原本的方法不具备事务的功能&#xff0c;运用Spring AOP的方式动态的增加了事务的功能&#xff0c;来确保数据库的数据的一致性。 只要开启事务的方法发生调用关系就一定存在事务的传…

Java 事务应用

一&#xff0c; 事务的一些基础知识简单回顾一下&#xff0c;讲的不是很深入&#xff0c;网上博客很多。 1&#xff0c;关于事务的四大特性&#xff1a;原子性、隔离性、一致性、持久性 本文不再赘述&#xff1b; 2&#xff0c;事务的隔离级别&#xff1a;读未提交&#xff0c;…

Java事务管理

事务的ACID属性&#xff1a;原子性(Atomicity )、一致性( Consistency )、隔离性或独立性( Isolation)和持久性(Durabilily) ACID 特性 A&#xff08;原子性&#xff09;事务的原子操作单元&#xff0c;对数据的修改&#xff0c;要么全部执行&#xff0c;要么全部不执行&#x…

java 事务级别_java事务隔离级别

事务隔离级别是由数据库系统实现的。 Java事务 1) 说到事务&#xff0c;不得不提的就是ACID特性&#xff0c;再次回顾&#xff1a; 原子性(atomicity)&#xff1a;组成事务处理的语句形成了一个逻辑单元&#xff0c;不能只执行其中的一部分。 一致性(consistency)&#xff1a…

Java中使用事务(注解实现)

Java中使用事务&#xff08;注解实现&#xff09; 事务的介绍 描述&#xff1a; 对于一个功能实现或者业务流程&#xff0c;要么全做&#xff0c;要么全不做&#xff01; 特性&#xff1a; ACID A - 原子性&#xff1a;执行的最小单位&#xff0c;要么全做&#xff0c;要么全…

JAVA的事务

要先知道什么是java中的事务? 事务: 一般是指要做的或所做的事情.专业术语是这样说的: 就是代码逻辑上的一组操作,这些操作要么全部成功,要么全部失败!举一个现实生活当中的例子: 1张三账上有2000元&#xff0c;李四账号也有2000元。张三要向李四转账1000元&#xff0c;正常来…

Java中的事务

一、事务概述 1. 什么是事务 事务是指对数据库的一系列的操作序列&#xff0c;数据库应用系统通过事务集来完成对数据的存取操作。 2. 事务的特性&#xff08;ACID原则&#xff09; 原子性&#xff08;Atomicity&#xff09;&#xff1a;一个事务的操作不可分割&#xff0c…

java事务总述

文章目录 一、java事务概述1.1、java事务简述1.2、Java事务的类型1.3、java事务的特性1.4、java事务的隔离级别1.5、spring事务的传播特性1.6、spring支持的事务管理类型 二、java事物使用2.1、XML配置2.2、事务使用方式 一、java事务概述 1.1、java事务简述 1、简介 事务(TR…

Java中的事务及使用

什么是事务&#xff1f; 事务&#xff08;Transaction&#xff09;&#xff0c;一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言&#xff08;如SQL&#xff0c;C或Java&am…