//01背包
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int W[30001];
int C[2001];
int R[2001][30001];
int main(){
int N,M;
cin>>N>>M;
for(int i=1;i<=N;i++)
cin>>C[i]>>W[i];
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
if(j>=C[i])
{
R[i][j]=max(R[i-1][j],R[i-1][j-C[i]]+W[i]);
}
else
{
R[i][j]=R[i-1][j];
}
cout<<R[N][M];
return 0;
}
//完全背包
#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];
return 0;
}
//多重背包
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],v[maxn],w[maxn],c[maxn];
int main(){
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
int x,y,z,k=0;
for(int i=1;i<=n;i++){
cin>>x>>y>>z;
int l=1;
while(z>=l){
v[++k]=x*l; w[k]=y*l;
z-=l;//每次减一是处理余数,计算余数大小 l*=2;
}
v[++k]=x*z; w[k]=y*z; //把 n[i]-2*k+1 分类 (处理余数)
}//其实只用快速将物品分类为对数级,后面操作解决为覆盖到的情况
假设有1000个苹果,现在要取n个苹果,如何取?正常的做法应该是将苹果一个一个拿出来,直到n个苹果被取出来。
又假设有1000个苹果和10只箱子,如何快速的取出n个苹果呢?可以在每个箱子中放 2^i (i<=0<=n)个苹果,也就是 1、2、4、8、16、32、64、128、256、489(最后的余数),相当于把十进制的数用二进制来表示,取任意n个苹果时,只要推出几只箱子就可以了。
for(int i=1;i<=k;i++) //相当于转化为数量为k的01背包
for(int j=m;j>=v[i];j--) //正常的滚动数组操作,之后直接套了 。从小到大更新覆盖所有情况
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[m];
return 0;
//没有多重背包题,代码只能存到A+B。。。。。。。。。。。
}
//混合背包
g[i]=0为完全背包; g[i]不为0,那g[i]的值为能购买数量
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],w[maxn],c[maxn],g[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]>>g[i];
for(int i=1;i<=n;i++)
if(g[i]==0){
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+c[i]);
}
else{
for(int k=1;k<=g[i];k++)
for(int j=m;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+c[i]);
}
cout<<f[m];
return 0;
}
//多维费用背包
{
//#include <iostream>
//#include <algorithm>
//
//using namespace std;
//
//const int maxn=2010,maxm=100;
//int f[maxm][maxn][maxn],w[maxn],c[maxn];
//
//int main(){
//
// ios::sync_with_stdio(false);
//
// int n,v,m;
//
// cin>>n>>v>>m;
//
// for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
//
// for(int i=1;i<=n;i++)
//
// for(int j=v;j>=1;j--)
//
// for(int z=m;z>=1;z--)
//
// if(w[i]<=v and c[i]<=m) f[i][j][z]=max(f[i-1][j][z],f[i-1][j-w[i]][z-c[i]]+1);
//
// else f[i][j][z]=f[i-1][j][z];
//
// cout<<f[n][v][m];
//
// return 0;
//}
}
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=3000;
int f[maxn][maxn],w[maxn],c[maxn];
int main(){
ios::sync_with_stdio(false);
int n,v,m;
cin>>n>>v>>m;
for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
for(int i=1;i<=n;i++)
for(int j=v;j>=w[i];j--) //两次滚动数组操作,增加一维空间,多一层循环
for(int z=m;z>=c[i];z--)
f[j][z]=max(f[j][z],f[j-w[i]][z-c[i]]+1);
cout<<f[v][m];
return 0;
}
// 滚动数组来优化果断要ac
分组背包
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
for(int i=1;i<=n;i++) cin>>w[i]>>c[i]>>P;
a[p][++a[p][0]]=i;
a[1][a[1][0]=1]=1;
a[1][a[1][0]=2]=2;
a[2][a[2][0]=1]=3;
a[2][a[2][0]=2]=4;
a[3][a[3][0]=1]=5;
a[3][a[3][0]=2]=6;
//设a[k][0]为其中一组的个数;
//设a[k][i]为其中一组中的成员序数;
cin>>m>>n>>t;// n为个数,t为组数;
for(int i=1;i<=n;i++){
cin>>w[i]>>c[i]>>p;
a[p][++z]=i; //z=0;
}
for(int k=1;k<=t;k++)
for(int j=m;j>=0;j--)
for(int i=1;i<=a[k][0];i++)
// for(int i=1;i<=a[k][0];i++)
//
// for(int j=m;j>=w[a[k][i]];j--) 如果这样写不保证每组只放一个,可能将多个放入;
if(j>=w[a[k][i]])
f[j]=max(f[j],f[j-w[a[k][i]]+c[a[k][i]]);
cout<<f[m];
return 0;
//前面推倒完就上代码;
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001,maxm=3000;
int f[maxn],w[maxn],c[maxn];
int a[maxm][maxm];
int main(){
ios::sync_with_stdio(false);
int m,n,p,z=0;
cin>>m>>n>>p;
for(int i=1;i<=n;i++){
cin>>w[i]>>c[i]>>p;
a[p][++a[p][0]]=i;//不用单一变量表示,是因为换组是时需重置,比较麻烦,所以用a[p][0];
}
for(int k=1;k<=n;k++)
for(int j=m;j>=0;j--)
for(int i=1;i<=a[k][i];i++)
if(j>=w[a[k][i]])
f[j]=max(f[j],f[j-w[a[k][i]]]+c[a[k][i]]);
cout<<f[m];
return 0;
}
背包的方案数
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=300001;
int f[maxn],a[maxn];
inline int read(){
int num=0,f=1; char c=getchar();
while(!isdigit(c)){
if(c=='-') f=-1; c=getchar();
}
while(isdigit(c)){
num=num*10+c-'0'; c=getchar();
}
return num*f;
}
int main(){
f[0]=1;
int n,m;
n=read(); m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++)
for(int j=m;j>=a[i];j--)
for(int k=1;k<=j/a[i];k++)//k层可以优化掉,这层并没有什么卵用
f[j]+=f[j-k*a[i]];//设f[j]为总额为 j的方案数,j-k*a[i]从上一总额推来
cout<<f[m];
return 0;
}
//3 10
//1
//2
//5
//
//f[10]+=f[9];
//....
//f[10]+=f[0]; // full f[10]=1;
//
//f[9]+=f[8]; // i=1时,i的每次更新都重新更新新的f值
int main(){
for(int i=1;i<=n;i++)
for(int j=a[i];j<=m;j++)
f[j]+=f[j-a[i]];//或者设f[j]为面值为j的方案数,从上一面值推来 j-a[i]为上一面值
}