算法 动态规划 01背包问题

article/2025/10/3 2:12:13

01背包

  • 问题分析
  • 代码实现
    • 从前往后拿,递归实现
    • 非递归实现
    • 非递归实现,自上向下填充

允接上一文章内容:
算法 动态规划: link.

问题分析

在这里插入图片描述
按照普通思维,首先想到应该为贪心算法,也就是计算每个物品重量价值比,将性价比高的物品装入背包,但是这并不是该问题的最优解,因为物品不是可分割的,不能按照重量价值比进行选择

这道问题的最优解应该通过动态规划求解,那么其递归方程式为:
在这里插入图片描述
在这里f(i,j),记为当背包容量为 j,现有 i 物品可拿,所能装进背包的最大价值
在这里插入图片描述
再者我们举例说明,假设背包总容量为8,现在有四件物品,其重量,价值分别为:

重量价值
23
34
45
58

在这里插入图片描述

首先我们是一个 f(4,8),即当容量为8,有4件物品可拿,所能装进背包的最大价值,接着第二步,选择对第四件物品拿与不拿,继而得到②③,f(3,3)+8,即容量为3,有 3 件物品可拿的最大价值加上 8(第四件物品的价值),或者 f(3,8),容量 8,有 3 件物品可拿的最大价值

随着我们的不断细分,最终得到最大值为12,也就是拿走第二件与第四件物品,对于上面的方式,无论是从后往前拿还是从前往后拿都是相同的

那么我们再看上面的递归方程式就很明了了
在这里插入图片描述

代码实现

从前往后拿,递归实现

int Knapsack(vector<int>& w, vector<int>& v, int i, int j, int n)
{if (i == n) //只有一个物品{return j >= w[i] ? v[i] : 0;}else{if (j < w[i])  //背包容量不足{return Knapsack(w, v, i + 1, j, n);}else{int maxv1 = Knapsack(w, v, i + 1, j, n);               //不装该物品int maxv2 = Knapsack(w, v, i + 1, j - w[i], n) + v[i]; //装该物品return maxv1 > maxv2 ? maxv1 : maxv2;}}
}int main()
{const int n = 5;   //物品数量const int c = 10;  //背包容量vector<int> w = { 0,2,2,6,6,4 }; //重量vector<int> v = { 0,6,3,5,4,6 }; //价值int maxv = Knapsack(w, v, 1, c, n);//i  jcout << maxv << endl;return 0;
}

非递归实现

void print_vect(const vector<vector<int>>& m)
{for (int i = 1; i < m.size(); ++i){for (int j = 1; j < m[i].size(); ++j){printf("%4d", m[i][j]);}printf("\n");}printf("\n");
}
int Knapsack2(vector<int>& w, vector<int>& v, int n, int c, vector<vector<int>>& m)
{if (n == 0) return 0;for (int j = 0; j <= c; ++j)  //填充最后一行{m[n][j] = j >= w[n] ? v[n] : 0;}print_vect(m);for (int i = n - 1; i >= 1; --i){for (int j = 1; j <= c; ++j){if (j >= w[i]){m[i][j] = max(m[i + 1][j], m[i + 1][j - w[i]] + v[i]);//通过容量与价值进行判断}else{m[i][j] = m[i - 1][j];}}print_vect(m);}
}
int main()
{const int n = 5;   //物品数量const int c = 10;  //背包容量vector<int> w = { 0,2,2,6,6,4 }; //重量vector<int> v = { 0,6,3,5,4,6 }; //价值vector<vector<int>> m(n + 1, vector<int>(c + 1, 0)); Knapsack2(w, v, n, c, m);return 0;
}
return 0;
}

在这里插入图片描述

在非递归实现中,我们首先传入了一个表格,其格式如下:
在这里插入图片描述
进入函数第一步,对最后一行进行填充,接下来自下向上每一行进行填充
在这里插入图片描述
m[i][j] = max(m[i + 1][j], m[i + 1][j - w[i]] + v[i]);
在填充过程中,例如黄色位置:j >= w[i],但是通过价值比较,4<6所以依然填入的是6,一直到 9 位置,10>6 则在此填入10
在这里插入图片描述

非递归实现,自上向下填充

void print_vect(const vector<vector<int>>& m)
{for (int i = 1; i < m.size(); ++i){for (int j = 1; j < m[i].size(); ++j){printf("%4d", m[i][j]);}printf("\n");}printf("\n");
}
void Knapsack3(vector<int>& w, vector<int>& v, int n, int c, vector<vector<int>>& m)
{for (int i = 1; i <= n; ++i) //行{for (int j = 1; j <= c; ++j) //列{if (j < w[i]){m[i][j] = m[i - 1][j]; //拷贝上面的}else{m[i][j] = std::max(m[i - 1][j], m[i - 1][j - w[i]] + v[i]);//判断放与不放的最优解}}print_vect(m);}
}int main()
{const int n = 5;   //物品数量const int c = 10;  //背包容量vector<int> w = { 0,2,2,6,6,4 }; //重量vector<int> v = { 0,6,3,5,4,6 }; //价值vector<vector<int>> m(n + 1, vector<int>(c + 1, 0)); Knapsack3(w, v, n, c, m);return 0;
}

在这里插入图片描述

最后的代码是,通过上述表中的变化,对每个物品加上bool值来确定是否取走了该物品

void backx(vector<int>& w, vector<vector<int>>& m, int n, int c,vector<bool>& x)
{for (int i = n; i >= 1; --i){if (m[i][c] != m[i - 1][c]) //该物品放入了背包{x[i] = true;c = c - w[i];}}
}
int main()
{const int n = 5;   //物品数量const int c = 10;  //背包容量vector<int> w = { 0,2,2,6,6,4 }; //重量vector<int> v = { 0,6,3,5,4,6 }; //价值vector<vector<int>> m(n + 1, vector<int>(c + 1, 0)); vector<bool> X(n + 1,false);Knapsack3(w, v, n, c, m);backx(w, m, n, c, X);for (int i = 1;i<=n;++i){if (X[i]){cout << i << endl;}}return 0;
}

在这里插入图片描述


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

相关文章

【动态规划】01背包问题

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位喜欢写作&#xff0c;计科专业大二菜鸟 &#x1f3e1;个人主页&#xff1a;starry陆离 &#x1f552;首发日期&#xff1a;2022年5月16日星期一 &#x1f30c;上期文章&#xff1a;【动态规划】最长上升子序列 &#x1f4…

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…