01背包问题
n种物品,每种物品只有1个,每种物品既有重量又有价值,背包最大重量为4,装满背包的最大价值是是多少?
物品 | weight | value |
物品0 | 1 | 15 |
物品1 | 3 | 20 |
物品2 | 4 | 30 |
暴力解法
每个物品有2种状态(取与不取),使用回溯算法暴力搜索枚举 时间复杂度O(2^n)
二维数组
动态规划
动规五部曲
1.明确dp数组的定义
dp[i][j] 任取[0,i]之间的物品,放进容量为j的背包里面,背包的最大价值是dp[i][j]
2.dp数组初始化
初始化第一行第一列即可其他的根据递推公式,都可由第一行第一列推导而来,所以初始化成何值都没有关系
3.递推公式
当前背包状态取决于放不放物品i
不放物品i:dp[i-1][j] 放物品i的最大价值: dp[i-1][j-weight[i]]+value[i]
dp[i][j] = dp[i-1][j] + dp[i-1][j-weight[i]] + value[i]
4.遍历顺序
5.打印dp数组
代码
遍历时,关于背包容量j与当前背包重量weight[i]一定要分类讨论
#include<bits/stdc++.h>
using namespace std;
int main(){
int M,N;
cin>>M>>N;//材料
std::vector<int> weight(M,0);
vector<int> value(M,0);
for(int i=0;i<M;i++){
cin>>weight[i];
}
for(int i=0;i<M;i++){
cin>>value[i];
}
//01背包问题
//1 定义dp数组
vector<vector<int>> dp(weight.size(),vector<int>(N+1,0));//0还要算一次背包容量
//2 初始化dp数组
//背包容量为0时 初始化为0
for(int i=0;i<weight.size();i++){
dp[i][0] = 0;
}
//放第一个物品0时
//若背包容量小于物品0的重量,则初始化为0
//若背包容量大于物品0的重量,则初始化为物品0的重量
//当j=0,即背包容量为0的情况已经讨论过了,所以这里直接取j=1
for(int j=1;j<=N;j++){
if(j<weight[0]) dp[0][j] = 0;
else dp[0][j] = value[0];
}
//3 遍历顺序
//先遍历物品,后遍历背包
for(int i=1;i<weight.size();i++){ //第一行已经初始化
for(int j=1;j<=N;j++){//第一列已经初始化了
if(j<weight[i]) dp[i][j] = dp[i-1][j];
//4 递推公式
else dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i]);
//cout<<dp[i][j]<<endl;
}
}
cout<<dp[M-1][N]<<endl;
return 0;
}
滚动数组(一维数组)
动态规划
动规五部曲
1)明确dp数组及下标i的含义
当前层是由上一层拷贝过来的,
dp[j] 背包容量为j的背包的最大价值是dp[j]
2)dp数组初始化
背包容量为0时,dp[0]=0
背包容量不为0时,根据递推公式,dp[j]=max(dp[j],dp[j-weight[i]]+value[i]),将dp[j]初始化为非负整数的最小值0,这样才不会掩盖递推公式求得的max的结果,所以dp[j]=0
3)递推公式
dp[j] = max(dp[j],dp[j-weight[i]]+value[i])
4)遍历顺序
!!!一定要先遍历物品,后倒序遍历背包!!!
反(先遍历背包,后遍历物品)
5)打印dp数组
!!!二维dp数组是每层完全隔开的,当前层的每一个值不受干扰,
一维dp数组每次重复利用,当前层的数值和当前层的旧值会产生冲突 所以遍历顺序不同!!!
代码
#include<vector>
#include<iostream>
using namespace std;
int main(){
int M,N;
cin>>M>>N;//材料
vector<int> weight(M,0);
vector<int> value(M,0);
for(int i=0;i<M;i++){
cin>>weight[i];
}
for(int i=0;i<M;i++){
cin>>value[i];
}
//01背包问题
//1 定义dp数组 //2 初始化dp数组
vector<int> dp(N+1,0);
//3 遍历顺序
//先遍历物品,后倒序遍历背包
for(int i=0;i<weight.size();i++){
for(int j=N;j>=weight[i];j--){
//4 递推公式
dp[j] = max(dp[j], dp[j-weight[i]]+value[i]);
}
}
cout<<dp[N]<<endl;
return 0;
}