今天来讲一下01背包问题,收获满满,感触颇深~
用上图举例
0-1背包问题1
/*
dp[i][j]:在[0,i]个物品中任选,放入容量为j的背包中的最大价值
有两种情况:1.不装(当前背包的容量装不下)2.不装
if(j<weight[i]) dp[i][j]=dp[i-1][j];
else dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);因为是最大价值,在能装下的情况下不装与装之间取最大值
0 1 2 3 4
0 0 15 15 15 15
1 0 15 15 20 35
2 0 15 15 20 35
*/
void Bag(){
vector<int>weight={1,2,4};//物品重量
vector<int>value={15,20,30};//物品价值
int maxWeight=4;//最大物品的重量
int m=weight.size();//物品个数
int n=maxWeight+1;
vector<vector<int>>dp(m,vector<int>(n,0));
//初始化第一列,即背包容量为0的时候,价值为0
for(int i=0;i<=m-1;i++){
dp[i][0]=0;
}
for(int j=1;j<=n-1;j++){
if(j>weight[0]){
dp[0][j]=value[0];
}
}
for(int i=1;i<=m-1;i++){
for(int j=1;j<=n-1;j++){
if(j<weight[i]) dp[i][j]=dp[i-1][j];
else dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
}
}
cout << dp[m - 1][n - 1] << endl;
}
0-1背包问题2
/*
利用滚动数组的思想初始化时二维数组变成一维数组,其实就是讲一个矩阵进行压缩
dp[j]:背包容量为j时的背包最大价值
dp[j] 0 1 2 3 4
背包0 0 15 15 15 15
背包1 0 15 15 20 35
背包2 0 15 15 20 35
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
初始化:dp[0]=0;从状态转移方程来看,因为求的是最大值,就应该把其置为一个非负的最小非0整数,所以就全部置为0,
这样才能让dp数组在递归公式的过程中取的最大的价值,而不是被初始值覆盖了。
vector<int>dp(n,0);
遍历顺序:首先得逆序遍历,为什么非得逆序:因为当前位置是由前面的位置推导而来,逆序保证了物品i只被放入一次,
如果正序遍历的话,也是因为当前位置是由前面的位置推导而来,而前面的位置已经放过了物品i了,物品i可能会被放入多次
for(int i=0;i<=m-1;i++){
for(int j=n-1;j>=weight[i];j--){
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}
}
*/
void Bag2(){
vector<int>weight={1,2,4};//物品重量
vector<int>value={15,20,30};//物品价值
int m=weight.size();//物品个数
int maxWeight=4;//最大物品的重量
int n=maxWeight+1;
vector<int>dp(n,0);
for(int i=0;i<=m-1;i++){
for(int j=n-1;j>=weight[i];j--){
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}
}
cout << dp[n-1];
}