//自己独创的完全背包,实际是01背包从前往后推的情况 (与3对照更好理解)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100010
int c[maxn],v[maxn],f[maxn];
int main(){
ios::sync_with_stdio(false);
int n,m,maxx=0;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>c[i]>>v[i];
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++)
if(j-c[i]>=0)
f[j]=max(f[j],f[j-c[i]]+v[i]);
cout<<f[m];
}
//其他人的完全背包 ,另一种从前往后推
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],w[maxn],c[maxn];
int main(){
ios::sync_with_stdio(false);
int n,m;
cin>>m>>n;
for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
for(int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
cout<<f[m];
}
//无可挑剔的01背包
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],w[maxn],c[maxn];
int main(){
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
for(int i=1;i<=n;i++)//保证每个物品只放一次
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+c[i]);//除了初次更新外,状态量必须有一个已经被更新过
cout<<f[m];
}
3 10
8 5
3 4
6 3
//理想下的推导方式
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],w[maxn],c[maxn];
int main(){
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
for(int j=1;j<=m;j++)//imaginative
for(int i=minn;i<=maxn;i+=x)
f[j]=max(f[j],f[j-c[i]]+v[i]);
}
//发现从前往后推时,可以成立如第一份代码,但无法保证物品被取至多一次
//但是要满足子问题重叠(有一个状态量已被更新过),肯定有两种思路,从后往前或从前往后
//所以此时实验从后往前推