(\)
(Description)
(N)个物品,每个物品有两个属性(w_i)和(v_i),代表价值和所能增加背包的容量,默认每一个物品体积均为(1),并且背包开始容量为(1),求合法状态下所能得到做多价值。
- (Nin [1,2000]),(w_iin [-10^6,10^6]),(v_iin [1,N])
(\)
(Solution)
-
首先将自己所用的那一个体积从自己的增加容量里扣掉,因为先用一个别人的容量再贡献出一个是合法的,所以可以直接扣除在自己的容量增量里。
-
设(f[i])表示还剩下的容量为(i)时,所能得到的最大价值,然后就是普通的(01)背包了。
-
注意到物品最多只有(2000)个,而总的可能带来的空间和可能会非常大,而有用的时候容量最多只需要(2000),所以转移的时候空间要取(min)。
-
注意到如果物品随意顺序做背包,那么下标为负可能也会有意义,可以等待后面的物品补上,所以应将物品按容量贡献排序处理,这样即不能出现所谓“替换位置”以补上空间的情况。
-
注意如果不会带来新的容量,那么这个物品的增量是(-1)根据(01)背包的设计原则,不能使用当前物品更新当前物品,所以此处应特判反向转移。
(\)
(Code)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 2010
#define R register
#define gc getchar
#define inf 2100000000
using namespace std;
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int n,ans,f[N];
struct sub{int v,num;}s[N];
inline bool cmp(sub x,sub y){return x.num>y.num;}
int main(){
n=rd();
for(R int i=1;i<=n;++i){s[i].num=rd()-1;s[i].v=rd();}
sort(s+1,s+1+n,cmp);
for(R int i=2;i<=n;++i) f[i]=-inf;
for(R int i=1;i<=n;++i){
if(s[i].num!=-1) for(R int j=n;j;--j) f[min(j+s[i].num,n)]=max(f[min(j+s[i].num,n)],f[j]+s[i].v);
else for(R int j=1;j<=n;++j) f[j-1]=max(f[j-1],f[j]+s[i].v);
for(R int i=0;i<=n;++i) ans=max(ans,f[i]);
}
for(R int i=0;i<=n;++i) ans=max(ans,f[i]);
printf("%d
",ans);
return 0;
}