1.问题描述
有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。
第 i件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
首先,动态规划的基本理念就是将大问题分解为性质相同的小问题,对每个小问题求的解记录下来,避免重复求解。其次,我们读题确定用动态规划求解后,可以列出递归方程,利用方程可以递推出最优解。
对于01背包问题,只有两种可能性:装/不装,
设f[i][j] i表示前i个物品,j表示当前容量 v[i]表示第i个物品的体积
对于装/不装 如果都满足限制条件,即可以同时出现,我们需要比较这两种情况的累计价值谁更大。
例:背包总容积V为5,以下是四件物品的体积和各自价值
体积vi | 价值wi | |
物品1 | 1 | 2 |
物品2 | 2 | 4 |
物品3 | 3 | 4 |
物品4 | 4 | 5 |
(行表示背包从0~V的体积变化,列表示第几个物品的序号,数组值表示前i件物品可以产生的最大价值)
0 | 1 | 2 | 3 | 4 | 5 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 2 | 2 | 2 | 2 | 2 |
2 | 0 | 2 | 4 | 6 | 6 | 6 |
3 | 0 | 2 | 4 | 6 | 6 | 8 |
4 | 0 | 2 | 4 | 6 | 6 | 8 |
如果装入第i个物品,则前i个物品的体积不能超过背包体积,体积改变,价值改变
即f[i][j]=f[i-1][j-v[i]]+w[i];
如果不装,则重量不变,价值不变
即f[i][j]=f[i-1][j];
代码如下所示
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int f[1011][2011];
int N,V;
int v[1011],w[2011];
int main(){
cin>>N >>V;
for(int i=1;i<=N;i++){
cin>>v[i] >>w[i];
}
for(int i=1;i<=N;i++){
for(int j=1;j<=V;j++){
f[i][j]=f[i-1][j];
if(v[i]<=j)//第i个装入
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
cout<<f[N][V]<<endl;
return 0;
}
2.代码优化
其实可以用一维数组来表示最优值,即将数组压缩
代码改动并不大,我们来看两个for循环中的语句:
for(int i=1;i<=N;i++){
for(int j=1;j<=V;j++){
f[i][j]=f[i-1][j];
if(v[i]<=j)//第i个装入
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
先看第一个对i进行循环的for语句,它的作用是将数据处理能遍历到每一行,有N个物品就有N行,所以我们只要保证第一个for循环存在,就知道这是到了第几行,因此f[i][j]可以直接写为f[j];
再来看对第二个for循环的处理,它是对每一列的遍历,强制去掉二维后f[j]=max(f[j],f[j-v[i]]+w[i]);
此时出现了问题,f[j-v[i]]是在第i行、第j-v[i]列的状态,但是我们需要的是第i-1行、第j-v[i]列的状态。
j按找从1~V变化显然不正确,会重复算第i行前面已经求出的解,因此我们使j逆序变化,
即for(j=V;j>=v[i];j--){
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
完整利用一维数组的代码为
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int f[1011];
int N,V;
int v[1011],w[1011];
int main(){
cin>>N >>V;
for(int i=1;i<=N;i++){
cin>>v[i] >>w[i];
}
for(int i=1;i<=N;i++){
for(int j=V;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
cout<<f[V]<<endl;
return 0;
}
至此,01背包——动态规划求解结束。
文章介绍了如何使用动态规划解决01背包问题,其中每个物品具有体积和价值,目标是选择物品使得总价值最大且不超过背包容量。通过建立递归方程并使用一维数组优化存储空间,实现了问题的解决方案,并给出了优化后的C++代码实现。
381

被折叠的 条评论
为什么被折叠?



