AC代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int w[N],v[N];
int f[N][N]={0};
int main()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(j>=v[i])
f[i][j]=max(f[i-1][j-v[i]]+w[i],f[i][j]);
}
}
cout<<f[n][m];
return 0;
}
相关解释:
这题是经典动态规划问题,也就是学动态规划必须会的题。这里要理解递推,也就是理解状态的转移。这里我们首先要进行状态表示,f[i][j]表示的是背包体积为j,从前i个物品中选所能获得的最大价值。从第一个物品开始遍历,对于每一个物品,我们都有两种情况,选还是不选。如果选,那么f[i][j]=f[i-1][j-v[i]]+w[i],这里的意思是如果你选了第i个物品,那么它所获得的最大价值就相当于你在前i-1个物品中选,体积变为j-v[i]所获得的最大价值加上你选择第i个物品的价值w[i]。那么如果你没选呢,就相当于你从前i-1个物品中选,背包体积为j的所获得的最大价值。此时在进行一个max操作取两者所能获得的最大价值。但是这里是不是可能会第i个物品的体积很大,而超过你所枚举的j(也就是你的背包的最大体积),那么此时就需要判断一下就可以了。这里主要的就是一个状态的表示和状态的计算。
补充:
这里的话,我们可以优化一下,为什么呢,因为有些题目的话。数据量会很大,那么就会mle,多重背包就会mle。此时我们就进行优化一下空间。从AC代码中我们可以注意到,f[i][j]只会和f[i-1][]相关,也就是第i层只会和第i-1层相关,前面的i-2层是无关的,所以我们没有必要开f[N][N],只需要开f[2][n]就可以了。这其实也可以优化成一维数组,但是优化为一维数组的话,不好理解,用滚动数组的话还好理解一些,其实两者相差不大。
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int w[N],v[N];
int f[2][N];
int main()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>v[i]>>w[i];
}
int old=1,new1=0;
for(int i=1;i<=n;i++)
{
swap(new1,old);
for(int j=1;j<=m;j++)
{
f[new1][j]=f[old][j];
if(j>=v[i])
f[new1][j]=max(f[old][j-v[i]]+w[i],f[new1][j]);
}
}
cout<<f[new1][m];
return 0;
}