一.题目描述
二.问题分析
这是一个典型的动态规划问题。
我们使用一个二维数组来解决问题,dp[i][j]表示从第1个到第i个物品中进行选取,装入容积为j的背包中商品的总价值。
其实这里隐含了一个初始条件,即dp[i][0]=0,即背包容量为0时,无论如何选取商品,其价值总为0。
如图所示,由于商品的编号从1开始,上图中箭头所指的元素值均为0。
有了初始条件,就需要dp的递推公式。
我们考虑最简单的一种情况,即商品的种类为1时。dp[1][j]的值完全取决于容量为j的背包能够装入多少件该商品。
此时,我们便能够将上图中绿色箭头所指的一行填上数字。
此时,我们再考虑复杂一点的情况,商品种类变为i。
也就是说,我们需要将上图表格中第i行填入。
此时考虑产生的最大价值,我们就需要去考虑i种商品。我们可以使用已经存在的数据,来对i种商品的最大价值进行构建。
背包的容积j从0开始依次递增到v,我们考虑dp[i][j]。
我们可以使用dp[i-1][j]的值对dp[i][j]进行初始化。注意:此时这个二维数组前i-1行的数据均填写完毕,均有初值。
dp[i][j]=dp[i-1][j],表示的含义就是不加入第i种产品,与此同时,我们还需要考虑加入第i种产品,问题来了,那需要加几个呢,所以嵌入了一个内循环,k从1开始,一直循环到背包容量所能承受的最大件数。每次都要去看,max(dp[i][j],dp[i-1][j-k*item[i].weight]+k*item[i].value),哪个值更大。注意,这里一定要用dp[i][j]。
最终,构建出了这个二维数组的所有值,dp[n][v]就是我们要的结果。
具体代码如下:
//小明的背包
#include <iostream>
using namespace std;
const int N=1e3+10;
int n,v;//n物品种类,v背包容积
struct Item{
int weight;
int value;
}item[N];
int dp[N][N]={0};//dp[i][j]表示从第1个到第i个物品中进行选取装入容积为j的背包中
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>v;
for(int i=0;i<n;i++){
cin>>item[i+1].weight>>item[i+1].value;
}
for(int i=1;i<=n;i++){//外层循环商品的种类
for(int j=0;j<=v;j++){//内层循环背包的容积
dp[i][j]=dp[i-1][j];//表示不放入第i个产品
for(int k=1;k*item[i].weight<=j;k++){
dp[i][j]=max(dp[i][j],dp[i-1][j-k*item[i].weight]+k*item[i].value);
}
}
}
cout<<dp[n][v]<<'\n';
return 0;
}