一、题目:
二、思路:
在01背包的基础上加一维k,即 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示前i件物品,体积为j的k次优解。
那么我们考虑怎样转移。
我们当前有两个序列,一列是不选当前物品,另一列是选当前物品,而且这两个序列是有序的。所以我们可以使用归并排序的思路,进行转移。
可以省掉i那一维。
附(张琪老师):
口头说不太能说清楚,看代码就明白了。
三、代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define FILEIN(s) freopen(s".in","r",stdin)
#define FILEOUT(s) freopen(s".out","w",stdout)
#define FILE(s) FILEIN(s);FILEOUT(s)
#define mem(s,v) memset(s,v,sizeof(s))
using namespace std;
template<class Type>
inline void read(Type &num){
Type x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
num=f*x;
}
const int maxn=205,maxk=55,maxv=5005;
int K,v,n;
int W[maxn],V[maxn];//体积,价值
int f[maxv][maxk];
LL ans;
int main(){
mem(f,0xcf);
read(K);read(v);read(n);
for(register int i=1;i<=n;++i){
read(W[i]);read(V[i]);
}
f[0][1]=0;
for(register int i=1;i<=n;++i){
for(register int j=v;j>=W[i];--j){
int t1=1,t2=1,len=0,tmp[maxk]={0};
while(t1+t2<=K+1){
// f[j]=max(f[j],f[j-W[i]]+V[i]); 这是原本的转移方程。
if(f[j][t1]>f[j-W[i]][t2]+V[i]){
tmp[++len]=f[j][t1++];
}
else{
tmp[++len]=f[j-W[i]][t2++]+V[i];
}
}
for(register int k=1;k<=K;++k){
f[j][k]=tmp[k];
}
}
}
for(register int k=1;k<=K;++k){
ans+=(LL)f[v][k];
}
printf("%lld\n",ans);
return 0;
}