news 2026/4/15 14:51:56

动态规划01背包问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
动态规划01背包问题

动态规划:01背包问题

情景

现在有一个容量有限的背包(比如能装10公斤的东西),现在有价值不同,重量也不同的几件物品,我们要怎样装才能让这个背包尽可能的装的价值最高

这就是为什么这个问题叫01背包问题,每个物品只有两种状态,放入(1)和不放入(0)

问题

有一个背包,最大承重W=10。有4件物品

  • 物品1:重量2,价值3
  • 物品2:重量3,价值4
  • 物品3:重量4,价值5
  • 物品4:重量5,价值6

问题:选择哪些物品放入背包,使总价值最大且总重量≤10?

普通解法
  1. 暴力计算

我们如果想把每个组合都试一遍,总能试出答案

#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intbruteForce01(vector<int>&values,vector<int>&weights,intcapacity){intn=values.size();intmaxVal=0;for(intmask=0;mask<(1<<n);mask++){intcurWeight=0,curValue=0;for(inti=0;i<n;i++){if(mask&(1<<i)){curWeight+=weights[i];curValue+=values[i];}}if(curWeight<=capacity){maxVal=max(maxVal,curValue);}}returnmaxVal;}intmain(){vector<int>values={3,4,5,6};vector<int>weights={2,3,4,5};intcapacity=10;cout<<"暴力解法结果: "<<bruteForce01(values,weights,capacity)<<endl;return0;}

确实算出了结果,但这个方法非常非常的麻烦,n = 4的情况下用了16种方法才试出答案,时间复杂度时O(n^2)

  1. 递归
#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intknapsackRecursive(inti,intremaining,vector<int>&values,vector<int>&weights){if(i==values.size())return0;intnotTake=knapsackRecursive(i+1,remaining,values,weights);inttake=0;if(remaining>=weights[i]){take=knapsackRecursive(i+1,remaining-weights[i],values,weights)+values[i];}returnmax(notTake,take);}intmain(){vector<int>values={3,4,5,6};vector<int>weights={2,3,4,5};intcapacity=10;cout<<"递归解法结果: "<<knapsackRecursive(0,capacity,values,weights)<<endl;return0;}

递归解法将这个二问题拆成小问题来解决,将选取这个物品和不选这个物品作比较,取最大值

这个解法看似没有暴力计算这么麻烦,但是在计算的过程中会有重叠子问题,重复的计算还是会带来效率的低下,那么为了避免重叠子问题,我们要使用动态规划

动态规划

二维数组

#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intknapsackDP(vector<int>&values,vector<int>&weights,intcapacity){intn=values.size();vector<vector<int>>dp(n+1,vector<int>(capacity+1,0));for(inti=1;i<=n;i++){intweight=weights[i-1];intvalue=values[i-1];for(intw=0;w<=capacity;w++){if(w<weight){dp[i][w]=dp[i-1][w];}else{dp[i][w]=max(dp[i-1][w],dp[i-1][w-weight]+value);}}}returndp[n][capacity];}intmain(){vector<int>values={3,4,5,6};vector<int>weights={2,3,4,5};intcapacity=10;cout<<knapsackDP(values,weights,capacity)<<endl;return0;}

我们创建了一个二维的数组,行代表考虑前i个物品,列代表背包当前的容量,两者合起来就是在考虑前i个物品时,背包容量为w时的最大值

现在将它初始化

现在对前k个物品进行外层遍历,在对背包的容量进行内层遍历,对于每个dp[i][w]我们都有两种情况,装的下和装不下,装不下那只能不选了,重在在于这个装的下,在这个时候,我们会有两种选择,装和不装,这时候就要比较不装的时候,和腾出该空间后剩下的价值比较

所以同样是比较,动态规划只需要计算一遍即可,比递归要快的多

一维数组

#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intknapsack01_1D(vector<int>&values,vector<int>&weights,intcapacity){intn=values.size();vector<int>dp(capacity+1,0);for(inti=0;i<n;i++){for(intw=capacity;w>=weights[i];w--){dp[w]=max(dp[w],dp[w-weights[i]]+values[i]);}}returndp[capacity];}intmain(){vector<int>values={3,4,5,6};vector<int>weights={2,3,4,5};intcapacity=10;cout<<knapsack01_1D(values,weights,capacity)<<endl;return0;}

dp[w]代表背包容量为w时的最大价值,仍然是熟悉的两层遍历,唯一不同的一点就是内层遍历变成了逆序遍历

为什么会这样?

这个数组只有一维,有限的空间使得计算时会包含当前的物品如果我们使用正序遍历,在dp的计算中会出现重复的计算,会存在一个物品被用了两次

所以我们使用逆序,从大容量向小容量思考,在计算dp时保证不含当前物品

解法对比表

比较维度暴力搜索普通递归动态规划(2D)动态规划(1D)
时间复杂度O(2ⁿ)O(2ⁿ)O(n×capacity)O(n×capacity)
是否重复计算大量重复(检查所有组合)大量重复(相同状态多次计算)无重复无重复
计算方向无方向自顶向下自底向上自底向上
代码复杂度简单中等中等中等(需理解逆序)
适用数据规模n≤15n≤20大中规模大规模
核心优势简单直观思维自然标准模板易理解空间最优速度快

总结

学习01背包问题更能理解动态规划的本质,理解其中空间换时间的思想,这篇文章是我之前动态规划的进一步学习,也为学习后边其他背包问题做铺垫

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 6:52:59

存储引擎内核:深入解析 LSM-Tree 原理与高吞吐写入实践

【精选优质专栏推荐】 《AI 技术前沿》 —— 紧跟 AI 最新趋势与应用《网络安全新手快速入门(附漏洞挖掘案例)》 —— 零基础安全入门必看《BurpSuite 入门教程(附实战图文)》 —— 渗透测试必备工具详解《网安渗透工具使用教程(全)》 —— 一站式工具手册《CTF 新手入门实战教…

作者头像 李华
网站建设 2026/4/14 12:23:45

保姆级教程:iPhone 某人短信消失?9 种解决方法,小白也会用

当某个联系人的短信突然从你的 iPhone 上消失时&#xff0c;你会感到很沮丧。你知道你没有删除它们&#xff0c;但整个对话却神秘地消失了。你并不孤单。许多 iPhone 用户在论坛上都报告了这个问题。无论是 iOS 故障、同步问题还是意外删除&#xff0c;本文都会从各个角度进行分…

作者头像 李华
网站建设 2026/4/14 10:41:16

31、进程间通信:信号、管道与套接字详解

进程间通信:信号、管道与套接字详解 1. 信号设置与处理 信号是进程间通信的重要方式之一,在处理信号时,我们可以设置不同的信号行为。以下是信号行为设置的相关模式: | 操作 | System V 模式 | POSIX 模式 | | — | — | — | | 忽略信号 | sigaction(signo,new,old) …

作者头像 李华
网站建设 2026/4/15 8:13:55

C语言归并排序

归并排序 归并排序——最常见的分治排序算法&#xff1b;把两个已经有序的数组合并成一个有序数组 一、归并排序思路 分&#xff1a;递归地把当前区间 [left, right] 一分为二&#xff0c;直到区间长度 ≤1。治&#xff1a;把两个已经有序的子区间合并成一个有序区间。合并时需…

作者头像 李华
网站建设 2026/4/13 20:25:49

java计算机毕业设计社区疫情防控管理系统 街区居民防疫信息综合平台 基层社区疫情联防联控小程序

计算机毕业设计社区疫情防控管理系统orcuw9&#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。疫情反复期间&#xff0c;社区卡口纸质登记、微信群接龙、人工电话追核酸造成数据碎片…

作者头像 李华
网站建设 2026/4/6 17:17:18

vue基于Spring Boot框架的 蛋糕购物商城的设计_k495g9n8

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;同时还支持java、ThinkPHP、Node.js、Spring B…

作者头像 李华