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; }
标签:vector,01,vol,value,int,背包,动态,dp From: https://www.cnblogs.com/Pworldlet/p/18604787