动态规划——01背包问题
01背包问题是一个经典的动态规划问题,虽然基础,之前做过很多遍,但是长时间不接触算法还是会忘记,故记录一下。
问题定义:
有 N 件物品和一个容量是V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
具体的练习题目见https://www.acwing.com/problem/content/description/2/
解题思路:
1、首先想一下暴力做法怎么解01背包:
每个物品有选与不选两种状态,用回溯算法遍历全部的可能性,时间复杂度也就是O(2^n)
2、dp数组的含义
首先明确二维dp数组的思路,然后可以优化为一维dp数组的做法
dp[i][j]表示:第[1,i]物品任取放入容量为j的背包中的最大价值
3、dp数组的大小
建议设置为dp[n+1][v+1],这样子不用对首行首列单独初始化
4、状态转移方程
dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i-1]]+w[i-1])
4、双重for循环的遍历先后(先for物品 还是 先for容量)
结论:
对于二维dp数组,先物品/先容量 都可以,因为dp[i][j]都是由上方和左上方得来的
对于一维dp数组(滚动数组),就只能先物品才行
代码:
二维dp:
#include<iostream> #include<vector> using namespace std; int main(){ int n,v; cin>>n>>v; vector<int> vol(n); vector<int> value(n); for(int i=0;i<n;i++){ cin>>vol[i]>>value[i]; } vector<vector<int>> dp(n+1,vector<int>(v+1)); for(int i=1;i<=n;i++){ for(int j=1;j<=v;j++){ if(j>=vol[i-1])dp[i][j]=max(dp[i-1][j],dp[i-1][j-vol[i-1]]+value[i-1]); else dp[i][j]=dp[i-1][j]; } } cout<<dp[n][v]; return 0; }
一维dp:
#include<iostream> #include<vector> using namespace std; int main(){ int n,v; cin>>n>>v; vector<int> vol(n); vector<int> value(n); for(int i=0;i<n;i++){ cin>>vol[i]>>value[i]; } vector<int> dp(v+1); for(int i=1;i<=n;i++){ for(int j=v;j>=vol[i-1];j--){ dp[j]=max(dp[j],dp[j-vol[i-1]]+value[i-1]); } } cout<<dp[v]; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具