$[ BZOJ 4247 ] $ 掛飾
阿新 • • 發佈:2018-09-09
register 別人 等待 get 1+n zoj 開始 def return
\(\\\)
\(Description\)
\(N\)個物品,每個物品有兩個屬性\(w_i\)和\(v_i\),代表價值和所能增加背包的容量,默認每一個物品體積均為\(1\),並且背包開始容量為\(1\),求合法狀態下所能得到做多價值。
- \(N\in [1,2000]\),\(w_i\in [-10^6,10^6]\),\(v_i\in [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\n",ans); return 0; }
$[\ BZOJ\ 4247\ ]\ $ 掛飾