#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int w[N], v[N];
/*int f[N][N];
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=0;j<=m;j++)
{
for(int k=0;k*v[i]<=j;k++)
{
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
}
}
}
cout<<f[n][m];
return 0;
}
//其动态规划方程为:f[i][j]=max(f[i-1][j-k*v[i]]+k*w[i]); 曲线救国得来.
*/
/*
进行第一次的优化:
首先,for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k*v[i]<=j;k++)
{
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
}
}
}
我们提取出其动态转移方程:f[i][j]=max(f[i-1][j-k*v[i]]+k*w[i])并对其进行展开有:
f[i][j]=max(f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w,f[i-1][j-3v]+3w,....)并将其与f[i][j-v]=max(f[i][j-(k+1)v]+(k+1)w[i]对比。
f[i][j-v]=max( f[i-1][j-v] ,f[i-1][j-2v]+w ,f[i-1][j-3v]+2w,....)
由上面两式一一对应下来可以得知f[i][j]从第二项开始的每一项与f[i][j-v]
的每一项相对应且都比f[i][j-v]的每一项多一个w,由此可见f[i][j]从第二项开始的
最大值为f[i][j-v]+w;
至此,动态转移方程优化为:f[i][j]=max(f[i-1][j],f[i][j-v]+w),从需要枚举k项
优化至只需比较两项,将一层循环优化掉,此时主代码为:
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(j>=v[i])f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
}
}
此时进行第二轮优化:将第一维去掉:
for(int i=1;i<=n;i++)
{
for(int j=v[i];j<=m;j++)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
若是与[01背包的最终代码](https://blog.youkuaiyun.com/llle_123/article/details/126024930?spm=1001.2014.3001.5501)相比会发现极其相似,但是因为01背包是从i-1层
来推第i层我们在跑代码的时候不能将第i-1层的数据提前覆盖掉所以j从大到小
但是完全背包是从第i层推出的第i层需要将其提前更新,故j从小到大;
*/
int f[N];
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 = v[i]; j <= m; j++) {
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}
cout << f[m];
return 0;
}